Merge branch 'main' of https://github.com/Discours/discoursio-webapp into feature/sse-test
This commit is contained in:
commit
6334afb6fa
132
package-lock.json
generated
132
package-lock.json
generated
|
@ -11,6 +11,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.0",
|
||||||
"i18next": "22.4.15",
|
"i18next": "22.4.15",
|
||||||
|
"i18next-icu": "2.3.0",
|
||||||
|
"intl-messageformat": "10.5.3",
|
||||||
"mailgun.js": "8.2.1",
|
"mailgun.js": "8.2.1",
|
||||||
"node-fetch": "3.3.1"
|
"node-fetch": "3.3.1"
|
||||||
},
|
},
|
||||||
|
@ -1991,6 +1993,50 @@
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@formatjs/ecma402-abstract": {
|
||||||
|
"version": "1.17.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.2.tgz",
|
||||||
|
"integrity": "sha512-k2mTh0m+IV1HRdU0xXM617tSQTi53tVR2muvYOsBeYcUgEAyxV1FOC7Qj279th3fBVQ+Dj6muvNJZcHSPNdbKg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@formatjs/intl-localematcher": "0.4.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@formatjs/fast-memoize": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@formatjs/icu-messageformat-parser": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-nF/Iww7sc5h+1MBCDRm68qpHTCG4xvGzYs/x9HFcDETSGScaJ1Fcadk5U/NXjXeCtzD+DhN4BAwKFVclHfKMdA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@formatjs/ecma402-abstract": "1.17.2",
|
||||||
|
"@formatjs/icu-skeleton-parser": "1.6.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@formatjs/icu-skeleton-parser": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.2.tgz",
|
||||||
|
"integrity": "sha512-VtB9Slo4ZL6QgtDFJ8Injvscf0xiDd4bIV93SOJTBjUF4xe2nAWOoSjLEtqIG+hlIs1sNrVKAaFo3nuTI4r5ZA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@formatjs/ecma402-abstract": "1.17.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@formatjs/intl-localematcher": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-BGdtJFmaNJy5An/Zan4OId/yR9Ih1OojFjcduX/xOvq798OgWSyDtd6Qd5jqJXwJs1ipe4Fxu9+cshic5Ox2tA==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@graphql-codegen/cli": {
|
"node_modules/@graphql-codegen/cli": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-3.2.2.tgz",
|
||||||
|
@ -10149,6 +10195,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/i18next-icu": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/i18next-icu/-/i18next-icu-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-x+j7kd5nDJCfbU53uwsMfXD7ALPu5uv0bqjAMQ5nVvXRoj1L7gkmswKtM3XDWYo4YUHf1jznlhSdPyy0xEwU+Q==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"intl-messageformat": "^10.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
@ -10441,6 +10495,17 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/intl-messageformat": {
|
||||||
|
"version": "10.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.3.tgz",
|
||||||
|
"integrity": "sha512-TzKn1uhJBMyuKTO4zUX47SU+d66fu1W9tVzIiZrQ6hBqQQeYscBMIzKL/qEXnFbJrH9uU5VV3+T5fWib4SIcKA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@formatjs/ecma402-abstract": "1.17.2",
|
||||||
|
"@formatjs/fast-memoize": "2.2.0",
|
||||||
|
"@formatjs/icu-messageformat-parser": "2.6.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/invariant": {
|
"node_modules/invariant": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||||
|
@ -17482,8 +17547,7 @@
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/tsutils": {
|
"node_modules/tsutils": {
|
||||||
"version": "3.21.0",
|
"version": "3.21.0",
|
||||||
|
@ -19561,6 +19625,50 @@
|
||||||
"integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==",
|
"integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@formatjs/ecma402-abstract": {
|
||||||
|
"version": "1.17.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.2.tgz",
|
||||||
|
"integrity": "sha512-k2mTh0m+IV1HRdU0xXM617tSQTi53tVR2muvYOsBeYcUgEAyxV1FOC7Qj279th3fBVQ+Dj6muvNJZcHSPNdbKg==",
|
||||||
|
"requires": {
|
||||||
|
"@formatjs/intl-localematcher": "0.4.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@formatjs/fast-memoize": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@formatjs/icu-messageformat-parser": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-nF/Iww7sc5h+1MBCDRm68qpHTCG4xvGzYs/x9HFcDETSGScaJ1Fcadk5U/NXjXeCtzD+DhN4BAwKFVclHfKMdA==",
|
||||||
|
"requires": {
|
||||||
|
"@formatjs/ecma402-abstract": "1.17.2",
|
||||||
|
"@formatjs/icu-skeleton-parser": "1.6.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@formatjs/icu-skeleton-parser": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.6.2.tgz",
|
||||||
|
"integrity": "sha512-VtB9Slo4ZL6QgtDFJ8Injvscf0xiDd4bIV93SOJTBjUF4xe2nAWOoSjLEtqIG+hlIs1sNrVKAaFo3nuTI4r5ZA==",
|
||||||
|
"requires": {
|
||||||
|
"@formatjs/ecma402-abstract": "1.17.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@formatjs/intl-localematcher": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-BGdtJFmaNJy5An/Zan4OId/yR9Ih1OojFjcduX/xOvq798OgWSyDtd6Qd5jqJXwJs1ipe4Fxu9+cshic5Ox2tA==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@graphql-codegen/cli": {
|
"@graphql-codegen/cli": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-3.2.2.tgz",
|
||||||
|
@ -25570,6 +25678,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"i18next-icu": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/i18next-icu/-/i18next-icu-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-x+j7kd5nDJCfbU53uwsMfXD7ALPu5uv0bqjAMQ5nVvXRoj1L7gkmswKtM3XDWYo4YUHf1jznlhSdPyy0xEwU+Q==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
@ -25777,6 +25891,17 @@
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"intl-messageformat": {
|
||||||
|
"version": "10.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.3.tgz",
|
||||||
|
"integrity": "sha512-TzKn1uhJBMyuKTO4zUX47SU+d66fu1W9tVzIiZrQ6hBqQQeYscBMIzKL/qEXnFbJrH9uU5VV3+T5fWib4SIcKA==",
|
||||||
|
"requires": {
|
||||||
|
"@formatjs/ecma402-abstract": "1.17.2",
|
||||||
|
"@formatjs/fast-memoize": "2.2.0",
|
||||||
|
"@formatjs/icu-messageformat-parser": "2.6.2",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"invariant": {
|
"invariant": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||||
|
@ -30923,8 +31048,7 @@
|
||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"tsutils": {
|
"tsutils": {
|
||||||
"version": "3.21.0",
|
"version": "3.21.0",
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.0",
|
||||||
"i18next": "22.4.15",
|
"i18next": "22.4.15",
|
||||||
|
"i18next-icu": "2.3.0",
|
||||||
|
"intl-messageformat": "10.5.3",
|
||||||
"mailgun.js": "8.2.1",
|
"mailgun.js": "8.2.1",
|
||||||
"node-fetch": "3.3.1"
|
"node-fetch": "3.3.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -212,7 +212,6 @@
|
||||||
"Nothing here yet": "There's nothing here yet",
|
"Nothing here yet": "There's nothing here yet",
|
||||||
"Nothing is here": "There is nothing here",
|
"Nothing is here": "There is nothing here",
|
||||||
"Notifications": "Notifications",
|
"Notifications": "Notifications",
|
||||||
"Registered since {{date}}": "Registered since {{date}}",
|
|
||||||
"Or continue with social network": "Or continue with social network",
|
"Or continue with social network": "Or continue with social network",
|
||||||
"Or paste a link to an image": "Or paste a link to an image",
|
"Or paste a link to an image": "Or paste a link to an image",
|
||||||
"Ordered list": "Ordered list",
|
"Ordered list": "Ordered list",
|
||||||
|
@ -250,6 +249,7 @@
|
||||||
"Quotes": "Quotes",
|
"Quotes": "Quotes",
|
||||||
"Reason uknown": "Reason unknown",
|
"Reason uknown": "Reason unknown",
|
||||||
"Recent": "Fresh",
|
"Recent": "Fresh",
|
||||||
|
"Registered since {date}": "Registered since {date}",
|
||||||
"Remove link": "Remove link",
|
"Remove link": "Remove link",
|
||||||
"Reply": "Reply",
|
"Reply": "Reply",
|
||||||
"Report": "Complain",
|
"Report": "Complain",
|
||||||
|
@ -327,6 +327,7 @@
|
||||||
"Upload": "Upload",
|
"Upload": "Upload",
|
||||||
"Upload error": "Upload error",
|
"Upload error": "Upload error",
|
||||||
"Upload video": "Upload video",
|
"Upload video": "Upload video",
|
||||||
|
"Uploading image": "Uploading image",
|
||||||
"Username": "Username",
|
"Username": "Username",
|
||||||
"Userpic": "Userpic",
|
"Userpic": "Userpic",
|
||||||
"Users": "Users",
|
"Users": "Users",
|
||||||
|
@ -408,5 +409,6 @@
|
||||||
"user already exist": "user already exists",
|
"user already exist": "user already exists",
|
||||||
"video": "video",
|
"video": "video",
|
||||||
"view": "view",
|
"view": "view",
|
||||||
"zine": "zine"
|
"zine": "zine",
|
||||||
|
"PublicationsWithCount": "{count, plural, =0 {no publications} one {{count} publication} other {{count} publications}}"
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,7 +222,6 @@
|
||||||
"Nothing here yet": "Здесь пока ничего нет",
|
"Nothing here yet": "Здесь пока ничего нет",
|
||||||
"Nothing is here": "Здесь ничего нет",
|
"Nothing is here": "Здесь ничего нет",
|
||||||
"Notifications": "Уведомления",
|
"Notifications": "Уведомления",
|
||||||
"Registered since {{date}}": "На сайте c {{date}}",
|
|
||||||
"Or continue with social network": "Или войдите через соцсеть",
|
"Or continue with social network": "Или войдите через соцсеть",
|
||||||
"Or paste a link to an image": "Или вставьте ссылку на изображение",
|
"Or paste a link to an image": "Или вставьте ссылку на изображение",
|
||||||
"Ordered list": "Нумерованный список",
|
"Ordered list": "Нумерованный список",
|
||||||
|
@ -264,6 +263,7 @@
|
||||||
"Quotes": "Цитаты",
|
"Quotes": "Цитаты",
|
||||||
"Reason uknown": "Причина неизвестна",
|
"Reason uknown": "Причина неизвестна",
|
||||||
"Recent": "Свежее",
|
"Recent": "Свежее",
|
||||||
|
"Registered since {date}": "На сайте c {date}",
|
||||||
"Release date...": "Дата выхода...",
|
"Release date...": "Дата выхода...",
|
||||||
"Remove link": "Убрать ссылку",
|
"Remove link": "Убрать ссылку",
|
||||||
"Reply": "Ответить",
|
"Reply": "Ответить",
|
||||||
|
@ -345,6 +345,7 @@
|
||||||
"Upload": "Загрузить",
|
"Upload": "Загрузить",
|
||||||
"Upload error": "Ошибка загрузки",
|
"Upload error": "Ошибка загрузки",
|
||||||
"Upload video": "Загрузить видео",
|
"Upload video": "Загрузить видео",
|
||||||
|
"Uploading image": "Загружаем изображение",
|
||||||
"Username": "Имя пользователя",
|
"Username": "Имя пользователя",
|
||||||
"Userpic": "Аватар",
|
"Userpic": "Аватар",
|
||||||
"Users": "Пользователи",
|
"Users": "Пользователи",
|
||||||
|
@ -434,5 +435,6 @@
|
||||||
"user already exist": "пользователь уже существует",
|
"user already exist": "пользователь уже существует",
|
||||||
"video": "видео",
|
"video": "видео",
|
||||||
"view": "просмотр",
|
"view": "просмотр",
|
||||||
"zine": "журнал"
|
"zine": "журнал",
|
||||||
|
"PublicationsWithCount": "{count, plural, =0 {нет публикаций} one {{count} публикация} few {{count} публикации} other {{count} публикаций}}"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { clsx } from 'clsx'
|
||||||
import styles from './AuthorBadge.module.scss'
|
import styles from './AuthorBadge.module.scss'
|
||||||
import { Userpic } from '../Userpic'
|
import { Userpic } from '../Userpic'
|
||||||
import { Author, FollowingEntity } from '../../../graphql/types.gen'
|
import { Author, FollowingEntity } from '../../../graphql/types.gen'
|
||||||
import { createMemo, createSignal, Show } from 'solid-js'
|
import { createMemo, createSignal, Match, Show, Switch } from 'solid-js'
|
||||||
import { formatDate } from '../../../utils'
|
import { formatDate } from '../../../utils'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '../../../context/localize'
|
||||||
import { Button } from '../../_shared/Button'
|
import { Button } from '../../_shared/Button'
|
||||||
|
@ -47,16 +47,22 @@ export const AuthorBadge = (props: Props) => {
|
||||||
<Userpic hasLink={true} isMedium={true} name={props.author.name} userpic={props.author.userpic} />
|
<Userpic hasLink={true} isMedium={true} name={props.author.name} userpic={props.author.userpic} />
|
||||||
<a href={`/author/${props.author.slug}`} class={styles.info}>
|
<a href={`/author/${props.author.slug}`} class={styles.info}>
|
||||||
<div class={styles.name}>{props.author.name}</div>
|
<div class={styles.name}>{props.author.name}</div>
|
||||||
<Show
|
<Switch
|
||||||
when={props.author.bio}
|
|
||||||
fallback={
|
fallback={
|
||||||
<div class={styles.bio}>
|
<div class={styles.bio}>
|
||||||
{t('Registered since {{date}}', { date: formatDate(new Date(props.author.createdAt)) })}
|
{t('Registered since {date}', { date: formatDate(new Date(props.author.createdAt)) })}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<Match when={props.author.bio}>
|
||||||
<div class={clsx('text-truncate', styles.bio)} innerHTML={props.author.bio} />
|
<div class={clsx('text-truncate', styles.bio)} innerHTML={props.author.bio} />
|
||||||
</Show>
|
</Match>
|
||||||
|
<Match when={props.author?.stat && props.author?.stat.shouts > 0}>
|
||||||
|
<div class={styles.bio}>
|
||||||
|
{t('PublicationsWithCount', { count: props.author.stat?.shouts ?? 0 })}
|
||||||
|
</div>
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
</a>
|
</a>
|
||||||
<Show when={props.author.slug !== session()?.user.slug}>
|
<Show when={props.author.slug !== session()?.user.slug}>
|
||||||
<div class={styles.actions}>
|
<div class={styles.actions}>
|
||||||
|
|
|
@ -193,12 +193,13 @@ export const AuthorCard = (props: Props) => {
|
||||||
<span class={clsx({ [styles.authorName]: !props.hasLink })}>{name()}</span>
|
<span class={clsx({ [styles.authorName]: !props.hasLink })}>{name()}</span>
|
||||||
</ConditionalWrapper>
|
</ConditionalWrapper>
|
||||||
</div>
|
</div>
|
||||||
{/*TODO: implement plurals by i18n*/}
|
|
||||||
<Show
|
<Show
|
||||||
when={props.author.bio && !props.hideBio}
|
when={props.author.bio && !props.hideBio}
|
||||||
fallback={
|
fallback={
|
||||||
props.showPublicationsCounter ? (
|
props.showPublicationsCounter ? (
|
||||||
<div class={styles.authorAbout}>{props.author.stat?.shouts} публикаций</div>
|
<div class={styles.authorAbout}>
|
||||||
|
{t('PublicationsWithCount', { count: props.author.stat?.shouts ?? 0 })}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
|
|
|
@ -44,6 +44,9 @@ import { EditorFloatingMenu } from './EditorFloatingMenu'
|
||||||
import './Prosemirror.scss'
|
import './Prosemirror.scss'
|
||||||
import { Image } from '@tiptap/extension-image'
|
import { Image } from '@tiptap/extension-image'
|
||||||
import { Footnote } from './extensions/Footnote'
|
import { Footnote } from './extensions/Footnote'
|
||||||
|
import { handleFileUpload } from '../../utils/handleFileUpload'
|
||||||
|
import { imageProxy } from '../../utils/imageProxy'
|
||||||
|
import { useSnackbar } from '../../context/snackbar'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
shoutId: number
|
shoutId: number
|
||||||
|
@ -51,6 +54,17 @@ type Props = {
|
||||||
onChange: (text: string) => void
|
onChange: (text: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allowedImageTypes = new Set([
|
||||||
|
'image/bmp',
|
||||||
|
'image/gif',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/jpg',
|
||||||
|
'image/png',
|
||||||
|
'image/tiff',
|
||||||
|
'image/webp',
|
||||||
|
'image/x-icon'
|
||||||
|
])
|
||||||
|
|
||||||
const yDocs: Record<string, Doc> = {}
|
const yDocs: Record<string, Doc> = {}
|
||||||
const providers: Record<string, HocuspocusProvider> = {}
|
const providers: Record<string, HocuspocusProvider> = {}
|
||||||
|
|
||||||
|
@ -61,6 +75,10 @@ export const Editor = (props: Props) => {
|
||||||
const [isCommonMarkup, setIsCommonMarkup] = createSignal(false)
|
const [isCommonMarkup, setIsCommonMarkup] = createSignal(false)
|
||||||
const [shouldShowTextBubbleMenu, setShouldShowTextBubbleMenu] = createSignal(false)
|
const [shouldShowTextBubbleMenu, setShouldShowTextBubbleMenu] = createSignal(false)
|
||||||
|
|
||||||
|
const {
|
||||||
|
actions: { showSnackbar }
|
||||||
|
} = useSnackbar()
|
||||||
|
|
||||||
const docName = `shout-${props.shoutId}`
|
const docName = `shout-${props.shoutId}`
|
||||||
|
|
||||||
if (!yDocs[docName]) {
|
if (!yDocs[docName]) {
|
||||||
|
@ -114,12 +132,73 @@ export const Editor = (props: Props) => {
|
||||||
content: 'figcaption image'
|
content: 'figcaption image'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const handleClipboardPaste = async () => {
|
||||||
|
try {
|
||||||
|
const clipboardItems = await navigator.clipboard.read()
|
||||||
|
|
||||||
|
if (clipboardItems.length === 0) return
|
||||||
|
const [clipboardItem] = clipboardItems
|
||||||
|
const { types } = clipboardItem
|
||||||
|
const imageType = types.find((type) => allowedImageTypes.has(type))
|
||||||
|
|
||||||
|
if (!imageType) return
|
||||||
|
const blob = await clipboardItem.getType(imageType)
|
||||||
|
const extension = imageType.split('/')[1]
|
||||||
|
const file = new File([blob], `clipboardImage.${extension}`)
|
||||||
|
|
||||||
|
const uplFile = {
|
||||||
|
source: blob.toString(),
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
file
|
||||||
|
}
|
||||||
|
|
||||||
|
showSnackbar({ body: t('Uploading image') })
|
||||||
|
const result = await handleFileUpload(uplFile)
|
||||||
|
|
||||||
|
editor()
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.insertContent({
|
||||||
|
type: 'capturedImage',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'figcaption',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: result.originalFilename
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'image',
|
||||||
|
attrs: {
|
||||||
|
src: imageProxy(result.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Paste Image Error]:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { initialContent } = props
|
const { initialContent } = props
|
||||||
|
|
||||||
const editor = createTiptapEditor(() => ({
|
const editor = createTiptapEditor(() => ({
|
||||||
element: editorElRef.current,
|
element: editorElRef.current,
|
||||||
editorProps: {
|
editorProps: {
|
||||||
attributes: {
|
attributes: {
|
||||||
class: 'articleEditor'
|
class: 'articleEditor'
|
||||||
|
},
|
||||||
|
transformPastedHTML(html) {
|
||||||
|
return html.replaceAll(/<img.*?>/g, '')
|
||||||
|
},
|
||||||
|
handlePaste: () => {
|
||||||
|
handleClipboardPaste()
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
extensions: [
|
extensions: [
|
||||||
|
@ -246,6 +325,7 @@ export const Editor = (props: Props) => {
|
||||||
TrailingNode,
|
TrailingNode,
|
||||||
Article
|
Article
|
||||||
],
|
],
|
||||||
|
enablePasteRules: [Link],
|
||||||
content: initialContent ?? null
|
content: initialContent ?? null
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ export const TopicBadge = (props: Props) => {
|
||||||
when={props.topic.body}
|
when={props.topic.body}
|
||||||
fallback={
|
fallback={
|
||||||
<div class={styles.description}>
|
<div class={styles.description}>
|
||||||
{props.topic.stat.shouts ?? 0} {t('Publications')}
|
{t('PublicationsWithCount', { count: props.topic.stat.shouts ?? 0 })}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
@ -35,8 +35,6 @@ export const AuthorView = (props: Props) => {
|
||||||
|
|
||||||
const { page } = useRouter()
|
const { page } = useRouter()
|
||||||
const author = createMemo(() => authorEntities()[props.authorSlug])
|
const author = createMemo(() => authorEntities()[props.authorSlug])
|
||||||
|
|
||||||
console.log('!!! author:', author())
|
|
||||||
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
|
||||||
const [isBioExpanded, setIsBioExpanded] = createSignal(false)
|
const [isBioExpanded, setIsBioExpanded] = createSignal(false)
|
||||||
const [followers, setFollowers] = createSignal<Author[]>([])
|
const [followers, setFollowers] = createSignal<Author[]>([])
|
||||||
|
|
|
@ -123,7 +123,7 @@ export const ProfileSettingsPage = () => {
|
||||||
<p class="description">{t('Here you can customize your profile the way you want.')}</p>
|
<p class="description">{t('Here you can customize your profile the way you want.')}</p>
|
||||||
<form onSubmit={handleSubmit} enctype="multipart/form-data">
|
<form onSubmit={handleSubmit} enctype="multipart/form-data">
|
||||||
<h4>{t('Userpic')}</h4>
|
<h4>{t('Userpic')}</h4>
|
||||||
<div class="pretty-form__item">
|
<div class="pretty-form__item" style={{ 'max-width': '50%' }}>
|
||||||
<Userpic
|
<Userpic
|
||||||
name={form.name}
|
name={form.name}
|
||||||
userpic={form.userpic}
|
userpic={form.userpic}
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { hydrate } from 'solid-js/web'
|
||||||
import type { PageContextBuiltInClientWithClientRouting } from 'vite-plugin-ssr/types'
|
import type { PageContextBuiltInClientWithClientRouting } from 'vite-plugin-ssr/types'
|
||||||
import type { PageContext } from './types'
|
import type { PageContext } from './types'
|
||||||
import { MetaProvider } from '@solidjs/meta'
|
import { MetaProvider } from '@solidjs/meta'
|
||||||
import { use as useI18next, init as initI18next } from 'i18next'
|
import i18next, { use as useI18next } from 'i18next'
|
||||||
|
import ICU from 'i18next-icu'
|
||||||
import HttpApi from 'i18next-http-backend'
|
import HttpApi from 'i18next-http-backend'
|
||||||
import * as Sentry from '@sentry/browser'
|
import * as Sentry from '@sentry/browser'
|
||||||
import { SENTRY_DSN } from '../utils/config'
|
import { SENTRY_DSN } from '../utils/config'
|
||||||
|
@ -30,7 +31,7 @@ export const render = async (pageContext: PageContextBuiltInClientWithClientRout
|
||||||
}
|
}
|
||||||
|
|
||||||
useI18next(HttpApi)
|
useI18next(HttpApi)
|
||||||
await initI18next({
|
await i18next.use(ICU).init({
|
||||||
// debug: true,
|
// debug: true,
|
||||||
supportedLngs: ['ru', 'en'],
|
supportedLngs: ['ru', 'en'],
|
||||||
fallbackLng: lng,
|
fallbackLng: lng,
|
||||||
|
|
|
@ -15,7 +15,7 @@ export const renderUploadedImage = (editor: Editor, image: UploadedFile) => {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: image.originalFilename
|
text: image.originalFilename ?? ''
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user