Updated Emojis (#8063)

Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
Alexander Platov
2025-02-21 18:02:20 +07:00
committed by GitHub
parent a604a1cc94
commit 4429d33c68
58 changed files with 1778 additions and 698 deletions
+158 -146
View File
@@ -451,12 +451,12 @@ importers:
'@rush-temp/model-mail':
specifier: file:./projects/model-mail.tgz
version: file:projects/model-mail.tgz
'@rush-temp/model-notification':
specifier: file:./projects/model-notification.tgz
version: file:projects/model-notification.tgz
'@rush-temp/model-my-space':
specifier: file:./projects/model-my-space.tgz
version: file:projects/model-my-space.tgz
'@rush-temp/model-notification':
specifier: file:./projects/model-notification.tgz
version: file:projects/model-notification.tgz
'@rush-temp/model-preference':
specifier: file:./projects/model-preference.tgz
version: file:projects/model-preference.tgz
@@ -625,6 +625,15 @@ importers:
'@rush-temp/mongo':
specifier: file:./projects/mongo.tgz
version: file:projects/mongo.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(gcp-metadata@5.3.0(encoding@0.1.13))(snappy@7.2.2)(socks@2.8.3)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
'@rush-temp/my-space':
specifier: file:./projects/my-space.tgz
version: file:projects/my-space.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
'@rush-temp/my-space-assets':
specifier: file:./projects/my-space-assets.tgz
version: file:projects/my-space-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
'@rush-temp/my-space-resources':
specifier: file:./projects/my-space-resources.tgz
version: file:projects/my-space-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
'@rush-temp/notification':
specifier: file:./projects/notification.tgz
version: file:projects/notification.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
@@ -649,15 +658,6 @@ importers:
'@rush-temp/panel':
specifier: file:./projects/panel.tgz
version: file:projects/panel.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
'@rush-temp/my-space':
specifier: file:./projects/my-space.tgz
version: file:projects/my-space.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
'@rush-temp/my-space-assets':
specifier: file:./projects/my-space-assets.tgz
version: file:projects/my-space-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
'@rush-temp/my-space-resources':
specifier: file:./projects/my-space-resources.tgz
version: file:projects/my-space-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
'@rush-temp/platform':
specifier: file:./projects/platform.tgz
version: file:projects/platform.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
@@ -1621,9 +1621,9 @@ importers:
email-addresses:
specifier: ^5.0.0
version: 5.0.0
emoji-regex:
specifier: ^10.1.0
version: 10.3.0
emojibase:
specifier: ^16.0.0
version: 16.0.0
esbuild:
specifier: ^0.24.2
version: 0.24.2
@@ -4163,7 +4163,7 @@ packages:
version: 0.0.0
'@rush-temp/desktop@file:projects/desktop.tgz':
resolution: {integrity: sha512-8we0EU2OgAaGXO+0DTj+BXro2vDokwXNGpKcVrzj9BbIvn6+3+BoRJJ1QcWwFa36XKnGuIKkkWMgMRdB6Quv9A==, tarball: file:projects/desktop.tgz}
resolution: {integrity: sha512-YKF8wyv3wcfxqTNHRQncoFfZt3HiJdnUYv7ZA35uqIAdY7Ib3qEhHH8JMBehGeBwMnXX576RBpeZAU0OYxS8ng==, tarball: file:projects/desktop.tgz}
version: 0.0.0
'@rush-temp/devmodel-resources@file:projects/devmodel-resources.tgz':
@@ -4343,15 +4343,15 @@ packages:
version: 0.0.0
'@rush-temp/mail-assets@file:projects/mail-assets.tgz':
resolution: {integrity: sha512-Lp1APt1DRMNrH2DhlOTTJjjIPhThHuc1+3Jj1fJU1ryH4FcJwCDFRw9InLEhjphf9cGC6z06EpgL3+3FtHOmJg==, tarball: file:projects/mail-assets.tgz}
resolution: {integrity: sha512-EY+m2n2E2Sm4zD0/n7psqlOwOH/zSinZE0zDfPLKZCFMF++7wuZ7cpkEz9NbL5zELQwqA7sk/G/IwUVIEXB/Kg==, tarball: file:projects/mail-assets.tgz}
version: 0.0.0
'@rush-temp/mail-resources@file:projects/mail-resources.tgz':
resolution: {integrity: sha512-8PtetoobhgQAiaGjqRf2aOgVY3Xh0KkyWTVLA2GIKaWY0lD0Vt69jDk1jptyXJOfkQLXRTSk7JxTs9lH96q8UQ==, tarball: file:projects/mail-resources.tgz}
resolution: {integrity: sha512-MArPZYwi2jollp/LHmrsx6wqyZzX/2XwjptpOg/10kADjpwo6wShL95ABMx5sCZo3+8paGXU1PipjnikbpNc0w==, tarball: file:projects/mail-resources.tgz}
version: 0.0.0
'@rush-temp/mail@file:projects/mail.tgz':
resolution: {integrity: sha512-khCqnHqt/MDtJv8eTx08ov9GkvC00wPeb1Q+QE5zk7xqbjK/QYJWPmdMRkvOJobCHLh2/g6ST2lgNbV938hrJA==, tarball: file:projects/mail.tgz}
resolution: {integrity: sha512-0UzQEN733mDUZKfsGvNq8ikfsbVjQgTFOzP7/+buwIfWgeZBqVCoCDJrk90ZQ38yp8dMgdWZ+OymfTZ4WNlb7g==, tarball: file:projects/mail.tgz}
version: 0.0.0
'@rush-temp/middleware@file:projects/middleware.tgz':
@@ -4371,7 +4371,7 @@ packages:
version: 0.0.0
'@rush-temp/model-all@file:projects/model-all.tgz':
resolution: {integrity: sha512-aDRtqYlITENsW02SJbs+KjoynFL+/QYQmYQVN6++EqsnAT+jHGPl/UpnmSr3ZMcALGcwTx61LKQ1nnxNen8tyA==, tarball: file:projects/model-all.tgz}
resolution: {integrity: sha512-Bo2UPIQp6MhS9V5sv9yJDdjxcjTy7u+2+QoGnGBweuD35Mwzy3MQIKnmf6XRLbvHTSkHno6ZKBMiZfWQReLgIw==, tarball: file:projects/model-all.tgz}
version: 0.0.0
'@rush-temp/model-analytics-collector@file:projects/model-analytics-collector.tgz':
@@ -4455,17 +4455,17 @@ packages:
version: 0.0.0
'@rush-temp/model-mail@file:projects/model-mail.tgz':
resolution: {integrity: sha512-Z2WZ+9IF0119TDZDyODrcI3ptuQLQ/h7WaxvbPIFsUQm+MI5VPV6hCNUBNp8if2XQLmSn0YByejtW1bSBz/WAg==, tarball: file:projects/model-mail.tgz}
resolution: {integrity: sha512-/GxdWziahn6TAFJ4/9V7YPatdGo68lWecWkOyMVdBtPFl9VcPsxYKt3cqWz9qk2G6UxV2k2bmI0qt8kg1anxUA==, tarball: file:projects/model-mail.tgz}
version: 0.0.0
'@rush-temp/model-my-space@file:projects/model-my-space.tgz':
resolution: {integrity: sha512-P/i9hwPmwSS8ol035oGdkhn66S+D3Knpj2/p65n0wB5oKaFG0Y9sM9NLGUIUAtiDmwGMfFhm2dq0OksEOxZ0BQ==, tarball: file:projects/model-my-space.tgz}
version: 0.0.0
'@rush-temp/model-notification@file:projects/model-notification.tgz':
resolution: {integrity: sha512-k7valecajKQwOhAeROASPm+RO2/D3xZSkan8Z09kmy+9dNLYBxQT/mr7k+HBdlzU4JD3fDQRP6EStyJBkLFZsQ==, tarball: file:projects/model-notification.tgz}
version: 0.0.0
'@rush-temp/model-my-space@file:projects/model-my-space.tgz':
resolution: {integrity: sha512-OxBDKFosN/3hsy9Ot0fDJTpzqFJvNLWxgJXtmculo1ksyKacMGZc4+9Ouxj49NFQ4JPl1UpBLZjaWPQ7xuyo3w==, tarball: file:projects/model-my-space.tgz}
version: 0.0.0
'@rush-temp/model-preference@file:projects/model-preference.tgz':
resolution: {integrity: sha512-r2RLrTIRHQ4txZegXOqXQfcPMJmA6HQz5i9EOi8RH7mGB+f6lqnBoYCf+mihfazPXLyF8NXbhPuNX1XHXMqvyg==, tarball: file:projects/model-preference.tgz}
version: 0.0.0
@@ -4694,6 +4694,18 @@ packages:
resolution: {integrity: sha512-aqU57iG6awiTX9qWSrzXMKyHSbt0V8mKAutQjE3uCx9FdPpnGiZjJflWsMS5PaZ4MdNazv2vUg4XPDHKCc4A/A==, tarball: file:projects/mongo.tgz}
version: 0.0.0
'@rush-temp/my-space-assets@file:projects/my-space-assets.tgz':
resolution: {integrity: sha512-62sXulipAWdzJz56yQZ2axXBdz7zHmd16Mbi5Edu/nqjoSlNcAxZvB6jUNi+kBi6qlO0jNzfNBRrQqQSi0JvMA==, tarball: file:projects/my-space-assets.tgz}
version: 0.0.0
'@rush-temp/my-space-resources@file:projects/my-space-resources.tgz':
resolution: {integrity: sha512-ze063pIWYIHyKghTiUGFua9X86uCshjgGnbZKY4WGjg6bIGhU2GTgDOiRDsGC0gWFKt+mag7hQ/nup2zBggY7Q==, tarball: file:projects/my-space-resources.tgz}
version: 0.0.0
'@rush-temp/my-space@file:projects/my-space.tgz':
resolution: {integrity: sha512-lZXMkLZnlmpSkjEj4lV2pxIaObjgAQ3OT4ktzUOzlpP1v3U78XKLJzRQ29SqVBYH+DcEHqL97znDPEGxzYHZKA==, tarball: file:projects/my-space.tgz}
version: 0.0.0
'@rush-temp/notification-assets@file:projects/notification-assets.tgz':
resolution: {integrity: sha512-+skvmrHYDNajtAeq2I5tAQXgK0u7WjzquNZXRe+F3zG81/0P3EDIz2k4qjN2HY6EBYZjJHqYsN1ZBWLBbQ2I2g==, tarball: file:projects/notification-assets.tgz}
version: 0.0.0
@@ -4726,18 +4738,6 @@ packages:
resolution: {integrity: sha512-cjwk9I0RxeNJQTgtbbcQlwiurbp+/T5MbiRnYTLWvxsMBVWnnxD5nToECUt1QdW/CjSSbPsaYP8hoMgt/AufCw==, tarball: file:projects/panel.tgz}
version: 0.0.0
'@rush-temp/my-space-assets@file:projects/my-space-assets.tgz':
resolution: {integrity: sha512-yGiP0aFiYA6RZiY4Ufqhk2egfhWvjEi3GOjcmLZ3eAl3samu/g4b3BcAKzo6SimMwKM2GQF+9oKHn1F/5LmSjA==, tarball: file:projects/my-space-assets.tgz}
version: 0.0.0
'@rush-temp/my-space-resources@file:projects/my-space-resources.tgz':
resolution: {integrity: sha512-dE2Jeu1rsu0l18l6oKj0Z+D99sS8fkuAcqoqh9alzavqquUvgGSXtTUB24l6Y6A0tbpshtAMLhmFSFgwPtSGHw==, tarball: file:projects/my-space-resources.tgz}
version: 0.0.0
'@rush-temp/my-space@file:projects/my-space.tgz':
resolution: {integrity: sha512-dBx6We9vl3uuETflughn1Q1jmxjzQdxZ0rf+OiZZ6lRM0u304BhlM7459AMcaZ76oxkqZ6ulRYVVxr8k7ZGHaA==, tarball: file:projects/my-space.tgz}
version: 0.0.0
'@rush-temp/platform-rig@file:projects/platform-rig.tgz':
resolution: {integrity: sha512-Ex4y6Gru0FdNgfJ8Q/TOIOZLrvmk+4eDiepGH95XOsHgcTQTfhHPfNwYBgC5yOqQrY9O8GDqWUZtV+KySEAQjg==, tarball: file:projects/platform-rig.tgz}
version: 0.0.0
@@ -4859,7 +4859,7 @@ packages:
version: 0.0.0
'@rush-temp/prod@file:projects/prod.tgz':
resolution: {integrity: sha512-VeRmwZegE4UJxGZfbKFP55egCMYIBuW6fCawXf1NHcXc93vnE6m9sax3s/O++FU3bMIhusbA0d74ZRRCCozxTw==, tarball: file:projects/prod.tgz}
resolution: {integrity: sha512-0fwdwfrUoXhanhn42lMUJOjDQmkbEur1NnpK4S8nitU/Bg8eyUil9ihjGj3hhVfSdwP7RAPk1iPNeRaAMCAnwQ==, tarball: file:projects/prod.tgz}
version: 0.0.0
'@rush-temp/products-assets@file:projects/products-assets.tgz':
@@ -5367,7 +5367,7 @@ packages:
version: 0.0.0
'@rush-temp/text-editor-resources@file:projects/text-editor-resources.tgz':
resolution: {integrity: sha512-JAu7yul5yHwjxWkBN9p1LW7HR8vAaRlf8Ioiyc7FYAKaQ1EBV05sCCpYsVayVpmU0vU92XzQffryB8TH/dZ6+A==, tarball: file:projects/text-editor-resources.tgz}
resolution: {integrity: sha512-PkvG582CT0XfnKC+4uNE1ZnwUgT9ywmfDmVr5vgcXti04Ntx1rB9VzTqnNDFI/A7h5dFAeEbR8s08gzgO6fdrw==, tarball: file:projects/text-editor-resources.tgz}
version: 0.0.0
'@rush-temp/text-editor@file:projects/text-editor.tgz':
@@ -5427,7 +5427,7 @@ packages:
version: 0.0.0
'@rush-temp/ui@file:projects/ui.tgz':
resolution: {integrity: sha512-tCUHrjveqVL6d3xRq8jtRIT7LdJUzDQFKavGeigF0kmaZxxSA9z5HBNCxszZu/vnK41+FVThVvwsExWnTr2ahA==, tarball: file:projects/ui.tgz}
resolution: {integrity: sha512-THkZLcaBxS58m9cqY59M3XZMTKNmmjb4CWSnh3nv8pzI0uuMHhZ9ldjS6zrzOLQJRlVB7XWuJBT/J5F9oLFs+w==, tarball: file:projects/ui.tgz}
version: 0.0.0
'@rush-temp/uploader-assets@file:projects/uploader-assets.tgz':
@@ -8405,6 +8405,13 @@ packages:
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
emojibase-regex@16.0.0:
resolution: {integrity: sha512-ZMp31BkzBWNW+T73of6NURL6nXQa5GkfKneOkr3cEwBDVllbW/2nuva7NO0J3RjaQ07+SZQNgPTGZ4JlIhmM2Q==}
emojibase@16.0.0:
resolution: {integrity: sha512-Nw2m7JLIO4Ou2X/yZPRNscHQXVbbr6SErjkJ7EooG7MbR3yDZszCv9KTizsXFc7yZl0n3WF+qUKIC/Lw6H9xaQ==}
engines: {node: '>=18.12.0'}
emojis-list@3.0.0:
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
engines: {node: '>= 4'}
@@ -19648,20 +19655,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@rush-temp/model-notification@file:projects/model-notification.tgz':
dependencies:
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.3.3)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
prettier: 3.2.5
typescript: 5.3.3
transitivePeerDependencies:
- supports-color
'@rush-temp/model-my-space@file:projects/model-my-space.tgz':
dependencies:
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.6.2)
@@ -19676,6 +19669,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@rush-temp/model-notification@file:projects/model-notification.tgz':
dependencies:
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.3.3)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
prettier: 3.2.5
typescript: 5.3.3
transitivePeerDependencies:
- supports-color
'@rush-temp/model-preference@file:projects/model-preference.tgz':
dependencies:
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3)
@@ -20540,6 +20547,97 @@ snapshots:
- supports-color
- ts-node
'@rush-temp/my-space-assets@file:projects/my-space-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))':
dependencies:
'@types/jest': 29.5.12
'@types/node': 20.11.19
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.6.2)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.6.2)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
prettier: 3.2.5
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.6.2)
typescript: 5.6.2
transitivePeerDependencies:
- '@babel/core'
- '@jest/types'
- babel-jest
- babel-plugin-macros
- esbuild
- node-notifier
- supports-color
- ts-node
'@rush-temp/my-space-resources@file:projects/my-space-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))':
dependencies:
'@types/jest': 29.5.12
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.6.2)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.6.2)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
eslint-plugin-svelte: 2.35.1(eslint@8.56.0)(svelte@4.2.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
fast-equals: 5.2.2
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
prettier: 3.2.5
prettier-plugin-svelte: 3.2.2(prettier@3.2.5)(svelte@4.2.19)
sass: 1.71.1
svelte: 4.2.19
svelte-check: 3.6.9(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19)
svelte-eslint-parser: 0.33.1(svelte@4.2.19)
svelte-loader: 3.2.0(svelte@4.2.19)
svelte-preprocess: 5.1.3(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19)(typescript@5.6.2)
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.6.2)
typescript: 5.6.2
transitivePeerDependencies:
- '@babel/core'
- '@jest/types'
- '@types/node'
- babel-jest
- babel-plugin-macros
- coffeescript
- esbuild
- less
- node-notifier
- postcss
- postcss-load-config
- pug
- stylus
- sugarss
- supports-color
- ts-node
'@rush-temp/my-space@file:projects/my-space.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))':
dependencies:
'@types/jest': 29.5.12
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.6.2)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.6.2)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
prettier: 3.2.5
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.6.2)
typescript: 5.6.2
transitivePeerDependencies:
- '@babel/core'
- '@jest/types'
- '@types/node'
- babel-jest
- babel-plugin-macros
- esbuild
- node-notifier
- supports-color
- ts-node
'@rush-temp/notification-assets@file:projects/notification-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))':
dependencies:
'@types/jest': 29.5.12
@@ -20795,97 +20893,6 @@ snapshots:
- supports-color
- ts-node
'@rush-temp/my-space-assets@file:projects/my-space-assets.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))':
dependencies:
'@types/jest': 29.5.12
'@types/node': 20.11.19
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.6.2)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.6.2)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
prettier: 3.2.5
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.6.2)
typescript: 5.6.2
transitivePeerDependencies:
- '@babel/core'
- '@jest/types'
- babel-jest
- babel-plugin-macros
- esbuild
- node-notifier
- supports-color
- ts-node
'@rush-temp/my-space-resources@file:projects/my-space-resources.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))':
dependencies:
'@types/jest': 29.5.12
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.6.2)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.6.2)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
eslint-plugin-svelte: 2.35.1(eslint@8.56.0)(svelte@4.2.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
fast-equals: 5.2.2
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
prettier: 3.2.5
prettier-plugin-svelte: 3.2.2(prettier@3.2.5)(svelte@4.2.19)
sass: 1.71.1
svelte: 4.2.19
svelte-check: 3.6.9(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19)
svelte-eslint-parser: 0.33.1(svelte@4.2.19)
svelte-loader: 3.2.0(svelte@4.2.19)
svelte-preprocess: 5.1.3(@babel/core@7.23.9)(postcss-load-config@4.0.2(postcss@8.4.35)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(postcss@8.4.35)(sass@1.71.1)(svelte@4.2.19)(typescript@5.6.2)
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.6.2)
typescript: 5.6.2
transitivePeerDependencies:
- '@babel/core'
- '@jest/types'
- '@types/node'
- babel-jest
- babel-plugin-macros
- coffeescript
- esbuild
- less
- node-notifier
- postcss
- postcss-load-config
- pug
- stylus
- sugarss
- supports-color
- ts-node
'@rush-temp/my-space@file:projects/my-space.tgz(@babel/core@7.23.9)(@jest/types@29.6.3)(@types/node@20.11.19)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))':
dependencies:
'@types/jest': 29.5.12
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.6.2)
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.6.2)
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.6.2)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
eslint-plugin-n: 15.7.0(eslint@8.56.0)
eslint-plugin-promise: 6.1.1(eslint@8.56.0)
jest: 29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3))
prettier: 3.2.5
ts-jest: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.11.19)(ts-node@10.9.2(@types/node@20.11.19)(typescript@5.3.3)))(typescript@5.6.2)
typescript: 5.6.2
transitivePeerDependencies:
- '@babel/core'
- '@jest/types'
- '@types/node'
- babel-jest
- babel-plugin-macros
- esbuild
- node-notifier
- supports-color
- ts-node
'@rush-temp/platform-rig@file:projects/platform-rig.tgz(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(svelte@4.2.19)':
dependencies:
'@typescript-eslint/parser': 6.21.0(eslint@8.56.0)(typescript@5.3.3)
@@ -26136,7 +26143,8 @@ snapshots:
date-fns: 2.30.0
date-fns-tz: 2.0.0(date-fns@2.30.0)
dompurify: 3.1.6
emoji-regex: 10.3.0
emojibase: 16.0.0
emojibase-regex: 16.0.0
eslint: 8.56.0
eslint-config-standard-with-typescript: 40.0.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(eslint@8.56.0))(eslint-plugin-n@15.7.0(eslint@8.56.0))(eslint-plugin-promise@6.1.1(eslint@8.56.0))(eslint@8.56.0)(typescript@5.3.3)
eslint-plugin-import: 2.29.1(eslint@8.56.0)
@@ -30186,6 +30194,10 @@ snapshots:
emoji-regex@9.2.2: {}
emojibase-regex@16.0.0: {}
emojibase@16.0.0: {}
emojis-list@3.0.0: {}
enabled@2.0.0: {}
@@ -45,6 +45,15 @@
return value !== undefined ? (typeof value === 'string' ? parseInt(value) : value) : undefined
}
const checkEmoji = (nodes: MarkupNode[]): boolean => {
const matches: boolean[] = []
nodes.forEach((node) => {
const reg = node.text?.match(/\P{Emoji}/gu)
matches.push(reg != null && reg.length > 0 && [65039, 65038, 8205].every((code) => code !== reg[0].charCodeAt(0)))
})
return matches.every((m) => !m)
}
</script>
{#if node}
@@ -60,7 +69,7 @@
{:else if node.type === MarkupNodeType.text}
{node.text}
{:else if node.type === MarkupNodeType.paragraph}
<p class="p-inline contrast" class:overflow-label={preview}>
<p class="p-inline contrast" class:overflow-label={preview} class:emojiOnly={checkEmoji(nodes)}>
{#if nodes.length > 0}
{#each nodes as node}
<Node {node} {preview} />
@@ -204,6 +213,10 @@
.imgContainer {
display: inline;
}
.emojiOnly {
font-size: 2rem;
line-height: 115%;
}
.img {
:global(img) {
+4
View File
@@ -186,6 +186,8 @@
--theme-checkbox-disabled: #999;
--theme-progress-color: #FFFFFF;
--theme-popup-color: #2A2939;
--theme-popup-trans-color: #2A2939ee;
--theme-popup-trans-gradient: linear-gradient(to bottom, #2A2939ff, #2A293900);
--theme-popup-hover: #333240;
--theme-popup-divider: rgba(255, 255, 255, .09);
--theme-popup-header: #3A3A47;
@@ -478,6 +480,8 @@
--theme-checkbox-disabled: #999;
--theme-progress-color: rgba(0, 0, 0, .5);
--theme-popup-color: #FFFFFF;
--theme-popup-trans-color: #FFFFFFee;
--theme-popup-trans-gradient: linear-gradient(to bottom, #FFFf, #FFF0);
--theme-popup-hover: #EBEBEB;
--theme-popup-divider: rgba(0, 0, 0, .09);
--theme-popup-header: #EBEBEB;
+2 -2
View File
@@ -286,7 +286,7 @@ input.search {
.items-baseline { align-items: baseline; }
.items-start { align-items: flex-start; }
.items-end { align-items: flex-end; }
.items-center { align-items: center; }
.items-center { align-items: center !important; }
.items-stretch { align-items: stretch; }
.self-start { align-self: flex-start; }
.self-end { align-self: flex-end; }
@@ -1046,7 +1046,7 @@ a.no-line {
.tertiary-textColor { color: var(--global-tertiary-TextColor) !important; }
.content-primary-color { color: var(--primary-button-color); }
.red-color { color: var(--highlight-red); }
.red-color { color: var(--highlight-red) !important; }
.error-color { color: var(--theme-error-color); }
.sunshine-text-color { color: var(--tag-accent-SunshineText) !important; }
+54 -25
View File
@@ -17,9 +17,6 @@
.hulyPopup-container {
display: flex;
flex-direction: column;
padding: 1px;
min-width: 15rem;
max-width: 15rem;
max-height: 22.625rem;
background: var(--theme-popup-color); // var(--global-popover-BackgroundColor);
border: 1px solid var(--theme-popup-divider); // var(--global-popover-BorderColor);
@@ -31,6 +28,11 @@
var(--global-popover-ShadowSpread)
var(--global-popover-ShadowColor);
&:not(.noPadding) { padding: 1px; }
&:not(.autoWidth) {
min-width: 16.5rem;
max-width: 16.5rem;
}
.hulyPopup-row {
display: flex;
justify-content: space-between;
@@ -97,11 +99,29 @@
border: 1px solid var(--theme-button-border);
border-radius: var(--extra-small-BorderRadius);
}
}
&:hover {
background-color: var(--theme-popup-hover); // var(--global-popover-hover-BackgroundColor);
}
&:not(.disabled, :disabled):hover {
background-color: var(--theme-popup-hover); // var(--global-popover-hover-BackgroundColor);
cursor: pointer;
}
&.disabled,
&:disabled {
cursor: default;
.hulyPopup-row__label { opacity: .5; }
}
}
.hulyPopup-group {
display: flex;
flex-direction: column;
flex-shrink: 0;
padding: var(--spacing-0_5);
}
.hulyPopup-divider {
flex-shrink: 0;
width: 100%;
height: 1px;
background-color: var(--theme-popup-divider);
}
}
@@ -339,12 +359,15 @@
width: auto;
min-height: 0;
min-width: 0;
max-width: 30rem;
background: var(--theme-popup-color);
border: 1px solid var(--theme-popup-divider);
border-radius: .5rem;
box-shadow: var(--theme-popup-shadow);
user-select: none;
&:not(.embedded) {
max-width: 30rem;
background: var(--theme-popup-color);
border-radius: .5rem;
border: 1px solid var(--theme-popup-divider);
box-shadow: var(--theme-popup-shadow);
}
&.isDock {
border-radius: 0;
@@ -518,7 +541,8 @@
.ap-menuHeader {
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--theme-popup-divider);
&:not(.noBorder) { border-bottom: 1px solid var(--theme-popup-divider); }
.tabs {
display: flex;
@@ -539,19 +563,24 @@
&:not(:last-child) { margin-right: .375rem; }
&:not(.selected, .disabled) { cursor: pointer; }
&.disabled { color: var(--theme-darker-color); }
&.selected {
color: var(--theme-caption-color);
&.selected { color: var(--theme-caption-color); }
}
&::after {
position: absolute;
content: '';
left: 0;
bottom: -1px;
width: 100%;
height: 2px;
background-color: var(--theme-link-color);
}
}
&:not(.bordered) .tab.selected::after {
position: absolute;
content: '';
left: 0;
bottom: -1px;
width: 100%;
height: 2px;
background-color: var(--theme-link-color);
}
&.bordered .tab {
min-height: 2.25rem;
border: 1px solid transparent;
border-radius: .375rem;
&.selected { border-color: var(--theme-button-border); }
}
}
}
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "Zobrazit méně",
"Search": "Hledat",
"SearchDots": "Hledám...",
"SearchResults": "Výsledky vyhledávání",
"Suggested": "Doporučeno",
"TimeTooltip": "{value}",
"SelectDate": "Vybrat datum",
@@ -75,14 +76,26 @@
"MM": "MM",
"YYYY": "RRRR",
"HH": "HH",
"GettingWorkDone": "Dokončování práce",
"ExpressYourself": "Vyjádřete se",
"Smileys": "Smajlíci",
"Nature": "Příroda",
"Symbols": "Symboly",
"SmileysAndPeople": "Smajlíky & Lidé",
"Components": "Součást",
"AnimalsAndNature": "Zvířata & Příroda",
"FoodAndDrink": "Jídlo & Pití",
"TravelAndPlaces": "Cestování a místa",
"Activities": "Aktivita",
"Objects": "Objekty",
"Food": "Jídlo",
"Symbols": "Symboly",
"Flags": "Příznak",
"FrequentlyUsed": "Často používané",
"GettingWorkDone": "Dokončování práce",
"DefaultSkinTone": "Výchozí tón pleti",
"NoTone": "Žádný tón",
"Light": "Světlo",
"MediumLight": "Středně světlý",
"Medium": "Střední",
"MediumDark": "Středně tmavý",
"Dark": "Tmavý",
"Remove": "Odstranit",
"NoResults": "Žádné Výsledky",
"MoreCount": "Ještě {count}",
"Spacious": "Prostorný",
"Compact": "Kompaktní",
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "Weniger anzeigen",
"Search": "Suchen",
"SearchDots": "Suchen...",
"SearchResults": "Suchergebnisse",
"Suggested": "Vorgeschlagen",
"TimeTooltip": "{value}",
"SelectDate": "Datum auswählen",
@@ -74,14 +75,26 @@
"MM": "MM",
"YYYY": "JJJJ",
"HH": "HH",
"GettingWorkDone": "Arbeit erledigen",
"ExpressYourself": "Ausdrücken",
"Smileys": "Smileys",
"Nature": "Natur",
"Symbols": "Symbole",
"SmileysAndPeople": "Smileys & Personen",
"Components": "Hauptkomponenten",
"AnimalsAndNature": "Tiere & Natur",
"FoodAndDrink": "Essen & Trinken",
"TravelAndPlaces": "Reisen & Orte",
"Activities": "Aktivitäten",
"Objects": "Objekte",
"Food": "Essen",
"Symbols": "Symbole",
"Flags": "Flags",
"FrequentlyUsed": "Häufig verwendet",
"GettingWorkDone": "Arbeit erledigen",
"DefaultSkinTone": "Standard-Hautton",
"NoTone": "Kein Ton",
"Light": "Leicht",
"MediumLight": "Mittelhell",
"Medium": "Mittel",
"MediumDark": "Mitteldunkel",
"Dark": "Dunkel",
"Remove": "Entfernen",
"NoResults": "Keine Ergebnisse",
"MoreCount": "{count} weitere",
"Spacious": "Geräumig",
"Compact": "Kompakt",
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "Show less",
"Search": "Search",
"SearchDots": "Search...",
"SearchResults": "Search Results",
"Suggested": "Suggested",
"TimeTooltip": "{value}",
"SelectDate": "Select date",
@@ -75,14 +76,26 @@
"MM": "MM",
"YYYY": "YYYY",
"HH": "HH",
"GettingWorkDone": "Getting work done",
"ExpressYourself": "Express yourself",
"Smileys": "Smileys",
"Nature": "Nature",
"Symbols": "Symbols",
"SmileysAndPeople": "Smileys & People",
"Components": "Components",
"AnimalsAndNature": "Animals & Nature",
"FoodAndDrink": "Food & Drink",
"TravelAndPlaces": "Travel & Places",
"Activities": "Activities",
"Objects": "Objects",
"Food": "Food",
"Symbols": "Symbols",
"Flags": "Flags",
"FrequentlyUsed": "Frequently used",
"GettingWorkDone": "Getting work done",
"DefaultSkinTone": "Default skin tone",
"NoTone": "No tone",
"Light": "Light",
"MediumLight": "Medium-light",
"Medium": "Medium",
"MediumDark": "Medium-dark",
"Dark": "Dark",
"Remove": "Remove",
"NoResults": "No Results",
"MoreCount": "{count} more",
"Spacious": "Spacious",
"Compact": "Compact",
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "Mostrar menos",
"Search": "Buscar",
"SearchDots": "Buscar...",
"SearchResults": "Resultados de la búsqueda",
"Suggested": "Sugerido",
"TimeTooltip": "{value}",
"SelectDate": "Seleccionar fecha",
@@ -75,14 +76,26 @@
"MM": "MM",
"YYYY": "AAAA",
"HH": "HH",
"GettingWorkDone": "Haciendo el trabajo",
"ExpressYourself": "Exprésate",
"Smileys": "Emoticonos",
"Nature": "Naturaleza",
"Symbols": "Símbolos",
"SmileysAndPeople": "Emoticonos y Personas",
"Components": "Componentes",
"AnimalsAndNature": "Animales y Naturaleza",
"FoodAndDrink": "Comida y Bebida",
"TravelAndPlaces": "Viajes y lugares",
"Activities": "Actividades",
"Objects": "Objetos",
"Food": "Comida",
"Symbols": "Símbolos",
"Flags": "Banderas",
"FrequentlyUsed": "De uso frecuente",
"GettingWorkDone": "Haciendo el trabajo",
"DefaultSkinTone": "Tono de piel predeterminado",
"NoTone": "Sin tono",
"Light": "Claro",
"MediumLight": "Medio-Сlaro",
"Medium": "Medio",
"MediumDark": "Medio-Oscuro",
"Dark": "Oscuro",
"Remove": "Eliminar",
"NoResults": "Sin Resultados",
"MoreCount": "{count} más",
"Spacious": "Espacioso",
"Compact": "Compacto",
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "Afficher moins",
"Search": "Rechercher",
"SearchDots": "Recherche...",
"SearchResults": "Résultats de la recherche",
"Suggested": "Suggéré",
"TimeTooltip": "{value}",
"SelectDate": "Sélectionner une date",
@@ -75,14 +76,26 @@
"MM": "MM",
"YYYY": "AAAA",
"HH": "HH",
"GettingWorkDone": "Faire le travail",
"ExpressYourself": "Exprime-toi",
"Smileys": "Émoticônes",
"Nature": "Nature",
"Symbols": "Symboles",
"SmileysAndPeople": "Smileys & Personnes",
"Components": "Composants",
"AnimalsAndNature": "Animaux & Nature",
"FoodAndDrink": "Nourriture & Boissons",
"TravelAndPlaces": "Voyages & Lieux",
"Activities": "Activités",
"Objects": "Objets",
"Food": "Nourriture",
"Symbols": "Symboles",
"Flags": "Drapeaux",
"FrequentlyUsed": "Fréquemment utilisé",
"GettingWorkDone": "Faire le travail",
"DefaultSkinTone": "Teint par défaut",
"NoTone": "Pas de tonalité",
"Light": "Clair",
"MediumLight": "Moyen-clair",
"Medium": "Moyen",
"MediumDark": "Moyen-foncé",
"Dark": "Foncé",
"Remove": "Supprimer",
"NoResults": "Aucun Résultat",
"MoreCount": "{count} de plus",
"Spacious": "Spacieux",
"Compact": "Compact",
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "Mostra meno",
"Search": "Cerca",
"SearchDots": "Cerca...",
"SearchResults": "Risultati ricerca",
"Suggested": "Suggerito",
"TimeTooltip": "{value}",
"SelectDate": "Seleziona data",
@@ -75,14 +76,26 @@
"MM": "MM",
"YYYY": "AAAA",
"HH": "HH",
"GettingWorkDone": "Completamento del lavoro",
"ExpressYourself": "Esprimi te stesso",
"Smileys": "Faccine",
"Nature": "Natura",
"Symbols": "Simboli",
"SmileysAndPeople": "Faccine & Persone",
"Components": "Componente",
"AnimalsAndNature": "Animali & Natura",
"FoodAndDrink": "Cibo & Bevande",
"TravelAndPlaces": "Viaggi e luoghi",
"Activities": "Attivita",
"Objects": "Oggetti",
"Food": "Cibo",
"Symbols": "Simboli",
"Flags": "Bandiera",
"FrequentlyUsed": "Usato frequentemente",
"GettingWorkDone": "Completamento del lavoro",
"DefaultSkinTone": "Tono della pelle predefinito",
"NoTone": "Nessun tono",
"Light": "Chiaro",
"MediumLight": "Medio-chiaro",
"Medium": "Medio",
"MediumDark": "Medio-scuro",
"Dark": "Scuro",
"Remove": "Rimuovere",
"NoResults": "Nessun risultato",
"MoreCount": "{count} in più",
"Spacious": "Ampio",
"Compact": "Compatto",
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "Mostrar menos",
"Search": "Pesquisar",
"SearchDots": "Pesquisar...",
"SearchResults": "Resultados da pesquisa",
"Suggested": "Sugerido",
"TimeTooltip": "{value}",
"SelectDate": "Selecionar data",
@@ -75,14 +76,26 @@
"MM": "MM",
"YYYY": "AAAA",
"HH": "HH",
"GettingWorkDone": "A fazer",
"ExpressYourself": "Expressa-te",
"Smileys": "Emoticons",
"Nature": "Natureza",
"Symbols": "Símbolos",
"SmileysAndPeople": "Carinhas & Pessoas",
"Components": "Componentes",
"AnimalsAndNature": "Animais & Natureza",
"FoodAndDrink": "Alimentos & Bebidas",
"TravelAndPlaces": "Viagens e Locais",
"Activities": "Actividades",
"Objects": "Objetos",
"Food": "Comida",
"Symbols": "Símbolos",
"Flags": "Bandeiras",
"FrequentlyUsed": "Frequentemente utilizado",
"GettingWorkDone": "A fazer",
"DefaultSkinTone": "Tom de pele padrão",
"NoTone": "Sem tom",
"Light": "Claro",
"MediumLight": "Médio Claro",
"Medium": "Médio",
"MediumDark": "Médio Escuro",
"Dark": "Escuro",
"Remove": "Remover",
"NoResults": "Sem Resultados",
"MoreCount": "{count} mais",
"Spacious": "Espaçoso",
"Compact": "Compacto",
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "Показать меньше",
"Search": "Поиск",
"SearchDots": "Поиск...",
"SearchResults": "Результаты поиска",
"Suggested": "Предложено",
"TimeTooltip": "{value}",
"SelectDate": "Выберите дату",
@@ -75,14 +76,26 @@
"MM": "ММ",
"YYYY": "ГГГГ",
"HH": "ЧЧ",
"GettingWorkDone": "Для работы",
"ExpressYourself": "Вырази себя",
"Smileys": "Смайлики",
"Nature": "Природа",
"Symbols": "Символы",
"SmileysAndPeople": "Эмоции & Люди",
"Components": "Компоненты",
"AnimalsAndNature": "Животные & Природа",
"FoodAndDrink": "Еда & Напитки",
"TravelAndPlaces": "Путешествия & Места",
"Activities": "Варианты досуга",
"Objects": "Объекты",
"Food": "Еда",
"Symbols": "Символы",
"Flags": "Флаги",
"FrequentlyUsed": "Часто используемые",
"GettingWorkDone": "Для работы",
"DefaultSkinTone": "Тон кожи по умолчанию",
"NoTone": "Без тона",
"Light": "Cветлый",
"MediumLight": "Cредне-светлый",
"Medium": "Средний",
"MediumDark": "Средне-темный",
"Dark": "Темный",
"Remove": "Удалить",
"NoResults": "Никаких результатов",
"MoreCount": "Ещё {count}",
"Spacious": "Просторный",
"Compact": "Компактный",
+19 -6
View File
@@ -26,6 +26,7 @@
"ShowLess": "显示更少",
"Search": "搜索",
"SearchDots": "搜索...",
"SearchResults": "搜寻结果",
"Suggested": "推荐",
"TimeTooltip": "{value}",
"SelectDate": "选择日期",
@@ -75,14 +76,26 @@
"MM": "月",
"YYYY": "年",
"HH": "小时",
"GettingWorkDone": "完成工作",
"ExpressYourself": "表达自己",
"Smileys": "表情符号",
"Nature": "自然",
"Symbols": "符号",
"SmileysAndPeople": "微笑与人",
"Components": "组件",
"AnimalsAndNature": "动物与自然",
"FoodAndDrink": "食物及饮品",
"TravelAndPlaces": "旅行和地点",
"Activities": "活动",
"Objects": "物体",
"Food": "食物",
"Symbols": "符号",
"Flags": "旗帜",
"FrequentlyUsed": "经常使用",
"GettingWorkDone": "完成工作",
"DefaultSkinTone": "默认肤色",
"NoTone": "违约情况",
"Light": "光",
"MediumLight": "中光",
"Medium": "中等",
"MediumDark": "中暗",
"Dark": "黑暗",
"Remove": "移走",
"NoResults": "没有结果",
"MoreCount": "还有 {count} 个",
"Spacious": "宽敞",
"Compact": "紧凑",
+2 -2
View File
@@ -45,11 +45,11 @@
"svelte": "^4.2.19",
"fast-equals": "^5.2.2",
"autolinker": "4.0.0",
"emoji-regex": "^10.1.0",
"date-fns": "^2.30.0",
"date-fns-tz": "^2.0.0",
"dompurify": "^3.1.6",
"@hcengineering/analytics": "^0.6.0"
"@hcengineering/analytics": "^0.6.0",
"emojibase": "^16.0.0"
},
"repository": "https://github.com/hcengineering/platform",
"publishConfig": {
@@ -1,315 +0,0 @@
<script lang="ts">
import emojiRegex from 'emoji-regex'
import { createEventDispatcher, getContext } from 'svelte'
import { IntlString } from '@hcengineering/platform'
import Label from './Label.svelte'
import Scroller from './Scroller.svelte'
import Emoji from './icons/Emoji.svelte'
import Food from './icons/Food.svelte'
import Nature from './icons/Nature.svelte'
import Objects from './icons/Objects.svelte'
import Places from './icons/Places.svelte'
import Symbols from './icons/Symbols.svelte'
import Work from './icons/Work.svelte'
import Palette from './icons/Palette.svelte'
import { tooltip } from '../tooltips'
import { AnySvelteComponent, emojiSP } from '../types'
import plugin from '../plugin'
import { fromCodePoint } from '../utils'
export let embedded = false
export let selected: string | undefined
export let disabled: boolean = false
interface Category {
id: string
label: IntlString
emojis: Array<string | undefined>
icon: AnySvelteComponent
}
let scrollElement: HTMLDivElement
const regex = emojiRegex()
const dispatch = createEventDispatcher()
const { currentFontSize } = getContext<{ currentFontSize: string }>('fontsize')
const emojiRowHeightPx = (currentFontSize === 'small-font' ? 14 : 16) * 2
const categories: Category[] = [
{
id: 'work',
label: plugin.string.GettingWorkDone,
emojis: [
String.fromCodePoint(0x1f440),
String.fromCodePoint(0x2705),
String.fromCodePoint(0x274c),
String.fromCodePoint(0x2795),
String.fromCodePoint(0x2796),
String.fromCodePoint(0x2757),
String.fromCodePoint(0x0031, 0xfe0f, 0x20e3),
String.fromCodePoint(0x0032, 0xfe0f, 0x20e3),
String.fromCodePoint(0x0033, 0xfe0f, 0x20e3),
String.fromCodePoint(0x1f44b),
String.fromCodePoint(0x1f44d),
String.fromCodePoint(0x1f44c),
String.fromCodePoint(0x1f525),
String.fromCodePoint(0x1f680)
],
icon: Work
},
{
id: 'smileys',
label: plugin.string.Smileys,
emojis: [
...getEmojis(0x1f600, 0x1f64b),
...getEmojis(0x1f64d, 0x1f64e),
...getEmojis(0x1f910, 0x1f917),
...getEmojis(0x1f920, 0x1f92f),
...getEmojis(0x1fae0, 0x1fae8),
...getEmojis(0x1f64f, 0x1f64f),
...getEmojis(0x1f64c, 0x1f64c),
...getEmojis(0x1f918, 0x1f91f),
...getEmojis(0x270a, 0x270d),
...getEmojis(0x1f90c, 0x1f90c),
...getEmojis(0x1faf0, 0x1faf8),
...getEmojis(0x1f446, 0x1f450),
...getEmojis(0x1f4aa, 0x1f4aa),
...getEmojis(0x1f9be, 0x1f9bf),
...getEmojis(0x1f9b5, 0x1f9b7)
],
icon: Emoji
},
{
id: 'nature',
label: plugin.string.Nature,
emojis: [
...getEmojis(0x1f408, 0x1f43e),
...getEmojis(0x1f980, 0x1f9ae),
...getEmojis(0x1f330, 0x1f343),
...getEmojis(0x1f300, 0x1f320),
...getEmojis(0x1f324, 0x1f32c, [0xfe0f]),
...getEmojis(0x2600, 0x2604, [0xfe0f])
],
icon: Nature
},
{
id: 'travels',
label: plugin.string.TravelAndPlaces,
emojis: [...getEmojis(0x1f5fb, 0x1f5ff), ...getEmojis(0x1f3e0, 0x1f3f0), ...getEmojis(0x1f680, 0x1f6a3)],
icon: Places
},
{
id: 'food',
label: plugin.string.Food,
emojis: [...getEmojis(0x1f345, 0x1f37f), ...getEmojis(0x1f32d, 0x1f32f)],
icon: Food
},
{
id: 'objects',
label: plugin.string.Objects,
emojis: [...getEmojis(0x1f4b6, 0x1f4fc)],
icon: Objects
},
{
id: 'symbols',
label: plugin.string.Symbols,
emojis: [
...getEmojis(0x00a9, 0x25fc, [0xfe0f]),
...getEmojis(0x2764, 0x2b07, [0xfe0f]),
...getEmojis(0x0023, 0x0039, [0xfe0f, 0x20e3]),
...getEmojis(0x1f532, 0x1f53d)
],
icon: Symbols
},
{
id: 'express',
label: plugin.string.ExpressYourself,
emojis: [
...generateSkinToneEmojis(0x1f44b),
...generateSkinToneEmojis(0x1f44d),
...generateSkinToneEmojis(0x1f44c),
...generateSkinToneEmojis(0x1f64c),
...generateSkinToneEmojis(0x1f44f),
...generateSkinToneEmojis(0x1f64f)
],
icon: Palette
}
]
let currentCategory = categories[0]
function getEmojis (startCode: number, endCode: number, postfix?: number[]): Array<string | undefined> {
return [...Array(endCode - startCode + 1).keys()].map((v) => {
const str = postfix ? fromCodePoint(v + startCode, ...postfix) : fromCodePoint(v + startCode)
if ([...str.matchAll(regex)].length > 0) return str
return undefined
})
}
function generateSkinToneEmojis (baseEmoji: number): string[] {
const skinTones = [0x1f3fb, 0x1f3fc, 0x1f3fd, 0x1f3fe, 0x1f3ff]
return skinTones.map((skinTone) => {
return String.fromCodePoint(baseEmoji, skinTone)
})
}
function handleScrollToCategory (categoryId: string) {
const labelElement = document.getElementById(categoryId)
if (labelElement) {
const emojisElement = labelElement.nextElementSibling as HTMLElement
scrollElement.scroll(0, emojisElement.offsetTop - (currentFontSize === 'small-font' ? 14 : 16) * 1.75)
}
}
function handleCategoryScrolled () {
const selectedCategory = categories.find((category) => {
const labelElement = document.getElementById(category.id)
if (!labelElement) {
return false
}
const emojisElement = labelElement.nextElementSibling as HTMLElement
return emojisElement.offsetTop + emojisElement.offsetHeight - emojiRowHeightPx > scrollElement.scrollTop
})
if (selectedCategory) {
currentCategory = selectedCategory
}
}
</script>
<div class={!embedded ? 'antiPopup antiPopup-withHeader popup' : 'flex-col'}>
<div class="flex-row-center popup-header">
{#each categories as category}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="element"
class:selected={currentCategory.id === category.id}
use:tooltip={{ label: category.label }}
on:click={() => {
handleScrollToCategory(category.id)
}}
>
<svelte:component
this={category.icon}
size="medium"
opacity={currentCategory.id === category.id ? '1' : '0.3'}
/>
</div>
{/each}
</div>
<div class="scrolling">
<Scroller
bind:divScroll={scrollElement}
fade={emojiSP}
noStretch
checkForHeaders
on:scrolledCategories={handleCategoryScrolled}
>
{#each categories as category}
<div id={category.id} class="scroll-header categoryHeader">
<Label label={category.label} />
</div>
<div class="palette ml-3">
{#each category.emojis as emoji}
{#if emoji !== undefined}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
class="element"
class:selected={emoji === selected}
class:disabled
on:click={() => {
if (disabled) return
dispatch('close', emoji)
}}
>
{emoji}
</div>
{/if}
{/each}
</div>
{/each}
</Scroller>
</div>
<div class="ap-space x2" />
</div>
<style lang="scss">
.popup {
height: 21.25rem;
}
.scrolling {
min-height: 0;
height: 16.5rem;
max-height: 16.5rem;
}
.popup-header {
margin: 0.75rem 0.75rem 0.5rem;
}
.scroll-header {
position: sticky;
flex-shrink: 0;
margin: 0.75rem 0.75rem 0.25rem;
padding: 0.25rem 0.75rem;
top: 0;
height: 1.5rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
color: var(--theme-caption-color);
background-color: var(--theme-popup-header);
border-radius: 0.25rem;
&:first-child {
margin-top: 0;
}
}
.palette {
display: flex;
flex-wrap: wrap;
// width: 19.25rem;
font-size: 1.25rem;
}
.element {
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
width: 1.75rem;
height: 1.75rem;
margin: 0.125rem;
padding: 0.25rem;
border-radius: 0.25rem;
color: var(--theme-content-color);
cursor: pointer;
&:hover {
&:not(&.disabled) {
color: var(--theme-caption-color);
background-color: var(--theme-popup-hover);
}
}
&.selected {
background-color: var(--theme-popup-header);
border: 1px solid var(--theme-popup-divider);
}
&.disabled {
cursor: default;
}
}
</style>
+11 -9
View File
@@ -106,26 +106,28 @@
if (divBar && divScroll) {
dispatch('divScrollTop', divScroll.scrollTop)
const trackH = divScroll.clientHeight - shiftTop - shiftBottom - 4
const visibleTrack = divScroll.clientHeight - shiftTop - shiftBottom - 4
const scrollH = divScroll.scrollHeight
const proc = scrollH / trackH
const proc = scrollH / visibleTrack
const newHeight = (divScroll.clientHeight - 4) / proc
const newHeightPx = newHeight + 'px'
if (divBar.style.height !== 'newHeight') {
divBar.style.height = newHeightPx
}
const _newHeight = visibleTrack / proc
const newHeight = _newHeight < 2 * fz ? 2 * fz : _newHeight
const newHeightPx = `${newHeight}px`
const procSpace = (scrollH - divScroll.clientHeight) / (visibleTrack - newHeight)
let newTop = '0px'
if (scrollDirection === 'vertical-reverse') {
newTop = divScroll.clientHeight + divScroll.scrollTop / proc - newHeight - shiftTop - 2 + 'px'
newTop = divScroll.clientHeight + divScroll.scrollTop / procSpace - newHeight - shiftTop - 2 + 'px'
} else {
newTop = divScroll.scrollTop / proc + shiftTop + 2 + 'px'
newTop = divScroll.scrollTop / procSpace + shiftTop + 2 + 'px'
}
if (divBar.style.top !== newTop) {
divBar.style.top = newTop
}
if (divBar.style.height !== newHeightPx) {
divBar.style.height = newHeightPx
}
if (mask === 'none') {
if (divBar.style.visibility !== 'hidden') {
divBar.style.visibility = 'hidden'
+13 -4
View File
@@ -16,7 +16,7 @@
import type { IntlString } from '@hcengineering/platform'
import { translateCB } from '@hcengineering/platform'
import { themeStore } from '@hcengineering/theme'
import { createEventDispatcher, onDestroy } from 'svelte'
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
import plugin from '../plugin'
import IconClose from './icons/Close.svelte'
import IconSearch from './icons/Search.svelte'
@@ -25,6 +25,9 @@
export let placeholder: IntlString = plugin.string.Search
export let placeholderParam: any | undefined = undefined
export let collapsed: boolean = false
export let autoFocus: boolean = false
export let width: string | undefined = undefined
export let delay: number = 500
let input: HTMLInputElement
let phTranslate: string = ''
@@ -42,14 +45,20 @@
timer = setTimeout(() => {
value = _search
dispatch('change', _search)
}, 500)
}, delay)
}
onDestroy(() => {
clearTimeout(timer)
})
onMount(() => {
if (autoFocus && input) {
autoFocus = false
input.focus()
}
})
</script>
<label class="searchInput-wrapper" class:collapsed class:filled={value && value !== ''}>
<label class="searchInput-wrapper" class:collapsed class:filled={value && value !== ''} style:width>
<div class="searchInput-icon">
<IconSearch size={'small'} />
</div>
@@ -179,7 +188,7 @@
&:active,
&:focus-within {
padding: 0 var(--spacing-0_5) 0 0;
max-width: 15rem;
// max-width: 15rem;
background-color: var(--input-BackgroundColor);
outline: 2px solid var(--global-focus-BorderColor);
outline-offset: 2px;
@@ -54,9 +54,11 @@
.tabs-container {
flex-shrink: 0;
flex-wrap: nowrap;
align-items: center;
width: 100%;
height: 4.5rem;
align-items: center;
min-width: 0;
min-height: 0;
border-bottom: 1px solid var(--theme-divider-color);
&:not(.noMargin) {
@@ -458,7 +458,7 @@
display: flex;
flex-direction: column;
padding: 0.5rem;
max-width: 50vw;
max-width: 60vw;
color: var(--theme-content-color);
background-color: var(--theme-popup-color);
border: 1px solid var(--theme-popup-divider);
@@ -0,0 +1,116 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
import { createEventDispatcher } from 'svelte'
import type { Emoji } from 'emojibase'
import type { EmojiWithGroup } from '.'
import { EmojiButton, getEmoji, getSkinTone, emojiStore } from '.'
import { Label, IconDelete, closeTooltip, ButtonBase } from '../..'
import plugin from '../../plugin'
import SkinToneTooltip from './SkinToneTooltip.svelte'
export let emoji: EmojiWithGroup
export let remove: boolean = false
export let skinTone: number = getSkinTone()
const dispatch = createEventDispatcher()
closeTooltip()
const haveSkins = Array.isArray(emoji.skins)
const combinedEmoji = haveSkins && (emoji?.skins?.length ?? 0) > 5
const clickRemove = (): void => {
dispatch('close', 'remove')
}
const getEmojiParts = (e: EmojiWithGroup): EmojiWithGroup[] => {
const def = $emojiStore[168]
const temp = e.skins?.find((skin) => Array.isArray(skin.tone) && skin.tone.length > 1)?.hexcode.split('-200D-')
if (temp === undefined || temp.length < 2) return [def, def]
const firstEmoji = getEmoji(temp[0].slice(0, -6))?.emoji ?? def
const secondEmoji = getEmoji(temp[temp.length - 1].slice(0, -6))?.emoji ?? def
return [firstEmoji, secondEmoji]
}
const emojiParts = getEmojiParts(emoji)
const combinedTones: number[] = [skinTone, skinTone]
const updateSkinTone = (result: CustomEvent<{ detail: number }>, index: number): void => {
const res = result.detail
if (typeof res === 'number') {
combinedTones[index] = res
const nextIndex = index === 1 ? 0 : 1
if (res === 0 && combinedTones[nextIndex] !== 0) combinedTones[nextIndex] = 0
else if (res !== 0 && combinedTones[nextIndex] === 0) combinedTones[nextIndex] = res
}
}
const getEmojiByTone = (e: EmojiWithGroup, [a, b]: number[]): Emoji | undefined => {
const equal = a === b
const noTone = a === 0
return equal && noTone
? e
: e.skins?.find((skin) =>
equal ? skin.tone === a : Array.isArray(skin.tone) && skin.tone[0] === a && skin.tone[1] === b
)
}
const getEmojiStringByTone = (e: EmojiWithGroup, [a, b]: number[]): string | undefined => {
return getEmojiByTone(e, [a, b])?.emoji
}
</script>
<div class="hulyPopup-container noPadding autoWidth">
{#if haveSkins}
{#if combinedEmoji && emojiParts?.length === 2}
<div class="hulyPopup-row disabled skins-row">
{#each new Array(2) as _, index}
<EmojiButton
emoji={emojiParts[index]}
skinTone={combinedTones[index]}
preview
showTooltip={{
component: SkinToneTooltip,
props: { emoji: emojiParts[index], selected: combinedTones[index] },
onUpdate: (result) => {
updateSkinTone(result, index)
}
}}
/>
{#if index === 0}
<ButtonBase
type={'type-button-icon'}
kind={'tertiary'}
size={'large'}
on:click={() => {
dispatch('close', getEmojiByTone(emoji, combinedTones))
}}
>
<span style:font-size={'2.5rem'}>{getEmojiStringByTone(emoji, combinedTones)}</span>
</ButtonBase>
{/if}
{/each}
</div>
{:else}
<div class="hulyPopup-row disabled skins-row">
{#each new Array((emoji.skins?.length ?? 5) + 1) as _, skin}
<EmojiButton {emoji} skinTone={skin} preview on:select={(result) => dispatch('close', result.detail)} />
{/each}
</div>
{/if}
{/if}
{#if remove}
{#if haveSkins}<div class="hulyPopup-divider" />{/if}
<div class="hulyPopup-group">
<button class="hulyPopup-row" on:click={clickRemove}>
<div class="hulyPopup-row__icon red-color"><IconDelete size={'small'} /></div>
<span class="hulyPopup-row__label red-color"><Label label={plugin.string.Remove} /></span>
</button>
</div>
{/if}
</div>
<style lang="scss">
.skins-row {
align-items: center;
}
</style>
@@ -0,0 +1,125 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
import { createEventDispatcher } from 'svelte'
import { getEmbeddedLabel } from '@hcengineering/platform'
import { tooltip, capitalizeFirstLetter, type EmojiWithGroup, type LabelAndProps } from '../../'
import { getEmoji } from '.'
import { type Emoji } from 'emojibase'
export let emoji: EmojiWithGroup
export let selected: boolean = false
export let disabled: boolean = false
export let preview: boolean = false
export let skinTone: number = 0
export let showTooltip: LabelAndProps | undefined = undefined
const dispatch = createEventDispatcher()
const getSkinsCount = (e: Emoji | EmojiWithGroup): number | undefined => {
return Array.isArray(e.skins) ? e.skins.length : undefined
}
let displayedEmoji: Emoji | EmojiWithGroup
$: _emoji = (getSkinsCount(emoji) ?? 0) > 0 ? emoji : getEmoji(emoji.hexcode)?.parent ?? emoji
$: skinIndex = _emoji?.skins?.findIndex((skin) => skin.tone === skinTone) ?? -1
$: displayedEmoji = skinTone > 0 && Array.isArray(_emoji.skins) && skinIndex > -1 ? _emoji.skins[skinIndex] : _emoji
</script>
{#if emoji}
<button
use:tooltip={showTooltip ?? { label: getEmbeddedLabel(capitalizeFirstLetter(displayedEmoji?.label ?? '')) }}
class="hulyPopupEmoji-button"
class:preview
class:selected
class:skins={_emoji?.skins !== undefined}
data-skins={getSkinsCount(_emoji)}
{disabled}
on:touchstart
on:contextmenu
on:click={() => {
if (disabled) return
dispatch('select', displayedEmoji)
}}
>
<span>{displayedEmoji.emoji}</span>
</button>
{/if}
<style lang="scss">
.hulyPopupEmoji-button {
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
line-height: 150%;
color: var(--theme-content-color);
&:not(.preview) {
margin: 0.125rem;
padding: 0.25rem;
width: 2.75rem;
height: 2.75rem;
font-size: 2rem;
border-radius: 0.75rem;
}
&.preview {
margin: 0;
padding: 0;
width: 2.25rem;
height: 2.25rem;
font-size: 1.75rem;
border-radius: 0.375rem;
}
span {
transform: translateY(1%);
pointer-events: none;
}
&:enabled:hover {
color: var(--theme-caption-color);
background-color: var(--theme-popup-hover);
}
&.selected {
background-color: var(--theme-popup-header);
border: 1px solid var(--theme-popup-divider);
}
:global(.mobile-theme) & {
width: 2rem;
height: 2rem;
font-size: 1.5rem;
border-radius: 0.25rem;
}
&.skins:not(.preview) {
position: relative;
border: 1px dashed var(--theme-button-border);
&:hover {
&::before {
content: '';
position: absolute;
top: -0.25rem;
right: -0.25rem;
width: 1rem;
height: 1rem;
border-radius: 50%;
background-color: var(--global-focus-BorderColor);
}
&::after {
content: attr(data-skins);
position: absolute;
top: 0.25rem;
right: 0.25rem;
font-size: 0.625rem;
font-weight: 700;
color: #fff;
transform: translate(50%, -50%);
}
}
}
}
</style>
@@ -0,0 +1,437 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
import { createEventDispatcher, onMount, onDestroy } from 'svelte'
import {
Label,
Scroller,
SearchInput,
tooltip,
deviceOptionsStore as deviceInfo,
showPopup,
eventToHTMLElement,
ButtonBase,
closeTooltip
} from '../../'
import plugin from '../../plugin'
import {
searchEmoji,
resultEmojis,
emojiStore,
generateSkinToneEmojis,
emojiCategories,
getFrequentlyEmojis,
addFrequentlyEmojis,
removeFrequentlyEmojis,
getEmoji,
getSkinTone,
setSkinTone
} from '.'
import type { EmojiWithGroup, EmojiCategory } from '.'
import EmojiButton from './EmojiButton.svelte'
import ActionsPopup from './ActionsPopup.svelte'
import SkinTonePopup from './SkinTonePopup.svelte'
import IconSearch from './icons/Search.svelte'
export let embedded = false
export let selected: string | undefined
export let disabled: boolean = false
const dispatch = createEventDispatcher()
closeTooltip()
let scrollElement: HTMLDivElement
const touchEvents = ['touchend', 'touchcancel', 'touchmove']
let skinTone: number = getSkinTone()
let shownSTM: boolean = false
let shownContext: boolean = false
$: emojiRowHeightPx = ($deviceInfo.fontSize ?? 16) * 2
$searchEmoji = ''
$: searching = $searchEmoji !== ''
const searchCategory: EmojiCategory[] = [
{
id: 'search-category',
label: plugin.string.SearchResults,
icon: IconSearch
}
]
let timer: any = null
emojiCategories.forEach((em, index) => {
if (em.id === 'frequently-used') {
emojiCategories[index].emojis = getFrequentlyEmojis()
}
if (em.emojisString !== undefined && Array.isArray(em.emojisString) && em.emojis === undefined) {
const tempEmojis: string[] = em.emojisString
const emojis: EmojiWithGroup[] = []
tempEmojis.forEach((te) => {
const e = $emojiStore.find((es) => es.hexcode === te)
if (e !== undefined) emojis.push(e)
})
emojiCategories[index].emojis = emojis
}
})
let emojisCat = emojiCategories.filter(
(em) => em.categories !== undefined || (Array.isArray(em.emojis) && em.emojis.length > 0)
)
let currentCategory = emojisCat[0]
function handleScrollToCategory (categoryId: string) {
if (searching && categoryId !== searchCategory[0].id) $searchEmoji = ''
setTimeout(() => {
const labelElement = document.getElementById(categoryId)
if (labelElement) {
const emojisElement = labelElement.nextElementSibling as HTMLElement
scrollElement.scroll(0, emojisElement.offsetTop - $deviceInfo.fontSize * 1.75)
}
}, 0)
}
function handleCategoryScrolled () {
const selectedCategory = emojisCat.find((category) => {
const labelElement = document.getElementById(category.id)
if (!labelElement) {
return false
}
const emojisElement = labelElement.nextElementSibling as HTMLElement
return emojisElement.offsetTop + emojisElement.offsetHeight - emojiRowHeightPx > scrollElement.scrollTop
})
if (selectedCategory) {
currentCategory = selectedCategory
}
}
const selectedEmoji = (event: CustomEvent<{ detail: EmojiWithGroup }>): void => {
if (event.detail === undefined || typeof event.detail !== 'object') return
const detail = event.detail as unknown as EmojiWithGroup
addFrequentlyEmojis(detail.hexcode)
dispatch('close', detail.emoji)
}
function openContextMenu (event: TouchEvent | MouseEvent, _emoji: EmojiWithGroup, remove: boolean): void {
event.preventDefault()
const temp = getEmoji(_emoji.hexcode)
const emoji = temp?.parent ?? temp?.emoji
if (emoji === undefined) return
clearTimer()
shownContext = true
showPopup(ActionsPopup, { emoji, remove }, eventToHTMLElement(event), (result) => {
if (result === 'remove') {
removeFrequentlyEmojis(emoji.hexcode)
const index = emojisCat.findIndex((ec) => ec.id === 'frequently-used')
if (index > -1) emojisCat[index].emojis = getFrequentlyEmojis()
emojisCat = emojisCat.filter(
(em) => em.categories !== undefined || (Array.isArray(em.emojis) && em.emojis.length > 0)
)
} else if (result !== undefined) {
addFrequentlyEmojis(result.hexcode)
dispatch('close', result.emoji)
}
shownContext = false
})
}
function handleContextMenu (event: MouseEvent, emoji: EmojiWithGroup, remove: boolean): void {
event.preventDefault()
if (Array.isArray(emoji.skins) || remove) openContextMenu(event, emoji, remove)
}
const clearTimer = (): void => {
clearTimeout(timer)
touchObserver(true)
}
const touchObserver = (remove: boolean = false): void => {
touchEvents.forEach((event) => {
if (remove) window.removeEventListener(event, clearTimer)
else window.addEventListener(event, clearTimer)
})
}
function clampedContextMenu (event: TouchEvent, emoji: EmojiWithGroup, remove: boolean): void {
if (timer == null && (Array.isArray(emoji?.skins) || remove)) {
touchObserver()
timer = setTimeout(function () {
if (!shownContext) openContextMenu(event, emoji, remove)
clearTimer()
}, 1000)
}
}
const showSkinMenu = (event: MouseEvent): void => {
shownSTM = true
showPopup(SkinTonePopup, { emoji: 0x1f590, selected: skinTone }, eventToHTMLElement(event), (result) => {
if (typeof result === 'number') {
skinTone = result
setSkinTone(skinTone)
}
shownSTM = false
})
}
let hidden: boolean = false
const checkScroll = (event: Event): void => {
if (timer != null) clearTimer()
const target = event.target as HTMLElement
if (target == null) return
hidden = target.scrollHeight - target.scrollTop - target.clientHeight < 5
}
onMount(() => {
if (scrollElement !== undefined) scrollElement.addEventListener('scroll', checkScroll)
})
onDestroy(() => {
if (scrollElement !== undefined) scrollElement.removeEventListener('scroll', checkScroll)
})
</script>
<div class="hulyPopupEmoji-container" class:embedded>
<div class="hulyPopupEmoji-header__tabs-wrapper">
<div class="hulyPopupEmoji-header__tabs">
{#each searching ? searchCategory.concat(emojisCat) : emojisCat as category}
<button
class="hulyPopupEmoji-header__tab"
class:selected={(searching && searchCategory[0].id === category.id) ||
(!searching && currentCategory.id === category.id)}
use:tooltip={{ label: category.label }}
on:click={() => {
handleScrollToCategory(category.id)
}}
>
<svelte:component this={category.icon} size={$deviceInfo.isMobile ? 'large' : 'x-large'} />
</button>
{/each}
<div
style:left={`${
(searching ? 0 : emojisCat.findIndex((ec) => ec.id === currentCategory.id)) *
($deviceInfo.isMobile ? 2 : 2.25)
}rem`}
class="hulyPopupEmoji-header__tab-cursor"
/>
</div>
</div>
<div class="hulyPopupEmoji-header__tools">
<SearchInput
value={$searchEmoji}
placeholder={plugin.string.SearchDots}
width={'100%'}
autoFocus
delay={50}
on:change={(result) => {
if (result.detail !== undefined) $searchEmoji = result.detail
else if (result.detail !== '') currentCategory = searchCategory[0]
}}
/>
<ButtonBase
type={'type-button-icon'}
hasMenu
pressed={shownSTM}
kind={'tertiary'}
size={'small'}
tooltip={{ label: plugin.string.DefaultSkinTone }}
on:click={showSkinMenu}
>
<span style:font-size={'1.5rem'}>{generateSkinToneEmojis(0x1f590)[skinTone]}</span>
</ButtonBase>
</div>
<Scroller bind:divScroll={scrollElement} checkForHeaders noStretch on:scrolledCategories={handleCategoryScrolled}>
{#each searching ? searchCategory : emojisCat as group}
{@const canRemove = group.id === 'frequently-used'}
{@const emojisGroup = searching
? $resultEmojis
: Array.isArray(group.emojis)
? group.emojis
: $resultEmojis.filter((re) => re.key === group.id)}
<div class="hulyPopupEmoji-group">
<div id={group.id} class="hulyPopupEmoji-group__header categoryHeader">
<Label label={searching && $resultEmojis.length === 0 ? plugin.string.NoResults : group.label} />
</div>
<div class="hulyPopupEmoji-group__palette">
{#each emojisGroup as emoji}
<EmojiButton
{emoji}
selected={emoji.emoji === selected}
{disabled}
{skinTone}
on:select={selectedEmoji}
on:touchstart={(event) => {
clampedContextMenu(event, emoji, canRemove)
}}
on:contextmenu={(event) => {
handleContextMenu(event, emoji, canRemove)
}}
/>
{/each}
</div>
</div>
{/each}
</Scroller>
{#if !hidden}<div class="hulyPopupEmoji-footer" />{/if}
</div>
<style lang="scss">
.hulyPopupEmoji-container {
position: relative;
display: flex;
flex-direction: column;
gap: 0.75rem;
padding-bottom: 0.75rem;
width: 100%;
height: 100%;
min-height: 0;
min-width: 0;
user-select: none;
&:not(.embedded) {
max-width: 28.625rem;
min-height: 28.5rem;
max-height: 28.5rem;
background: var(--theme-popup-color); // var(--global-popover-BackgroundColor);
border: 1px solid var(--theme-popup-divider); // var(--global-popover-BorderColor);
border-radius: var(--small-BorderRadius);
box-shadow: var(--global-popover-ShadowX) var(--global-popover-ShadowY) var(--global-popover-ShadowBlur)
var(--global-popover-ShadowSpread) var(--global-popover-ShadowColor);
:global(.mobile-theme) & {
max-width: calc(100vw - 2rem);
max-height: calc(100vw - 2rem);
.hulyPopupEmoji-header__tabs-wrapper {
overflow-x: auto;
min-width: 0;
}
}
}
.hulyPopupEmoji-header__tools,
.hulyPopupEmoji-header__tabs-wrapper,
.hulyPopupEmoji-header__tabs,
.hulyPopupEmoji-header__tab {
display: flex;
align-items: center;
flex-shrink: 0;
min-width: 0;
min-height: 0;
}
.hulyPopupEmoji-header__tabs-wrapper {
width: 100%;
padding: 0.25rem 0.75rem;
border-bottom: 1px solid var(--theme-popup-divider);
}
.hulyPopupEmoji-header__tabs {
position: relative;
gap: 0.25rem;
margin: 0.25rem 0;
width: 100%;
}
.hulyPopupEmoji-header__tab {
justify-content: center;
width: 2rem;
height: 2rem;
color: var(--theme-halfcontent-color);
transition: color 0.1s linear;
:global(.mobile-theme) & {
width: 1.75rem;
height: 1.75rem;
}
:global(svg) {
transform: scale(0.8);
transition: transform 0.15s ease-in-out;
}
&.selected {
color: var(--theme-caption-color);
:global(svg) {
transform: scale(1);
}
}
&:enabled:hover {
color: var(--theme-content-color);
}
}
.hulyPopupEmoji-header__tab-cursor {
position: absolute;
bottom: calc(-0.5rem - 1px);
width: 2rem;
height: 0.25rem;
background-color: var(--global-focus-BorderColor);
transition: left 0.15s ease-in-out;
:global(.mobile-theme) & {
width: 1.75rem;
}
}
.hulyPopupEmoji-header__tools {
gap: 0.5rem;
padding: 0 0.75rem;
}
.hulyPopupEmoji-group {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
min-width: 0;
min-height: 0;
&__header {
position: sticky;
flex-shrink: 0;
margin: 0.75rem 0.75rem 0.25rem;
padding: 0.25rem 0.375rem;
top: 0;
height: 1.5rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
text-shadow: 0 0 0.25rem var(--theme-popup-color);
color: var(--theme-caption-color);
border-radius: 0.25rem;
z-index: 1;
pointer-events: none;
&:first-child {
margin-top: 0;
}
&::before {
content: '';
position: absolute;
top: -1px;
left: 0;
width: 100%;
height: 150%;
background: var(--theme-popup-trans-gradient);
z-index: -1;
}
}
&__palette {
display: flex;
flex-wrap: wrap;
flex-shrink: 0;
margin-left: 0.75rem;
font-size: 1.25rem;
}
}
.hulyPopupEmoji-group + .hulyPopupEmoji-group {
margin-top: 0.5rem;
}
.hulyPopupEmoji-footer {
position: absolute;
left: 50%;
bottom: 0.75rem;
width: calc(100% - 1.5rem);
height: 1rem;
background: var(--theme-popup-trans-gradient);
transform-origin: center;
transform: translateX(-50%) rotate(180deg);
z-index: 1;
pointer-events: none;
}
}
</style>
@@ -0,0 +1,40 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
import { createEventDispatcher } from 'svelte'
import type { Emoji } from 'emojibase'
import { Label, closeTooltip, ModernCheckbox } from '../../'
import { generateSkinToneEmojis, skinTones, getEmojiCode } from '.'
import type { EmojiWithGroup } from '.'
export let emoji: number | number[] | string | Emoji | EmojiWithGroup
export let selected: number
const dispatch = createEventDispatcher()
closeTooltip()
const skins: string[] = generateSkinToneEmojis(getEmojiCode(emoji))
</script>
<div class="hulyPopup-container noPadding">
<div class="hulyPopup-group">
{#each skins as skin, index}
{@const disabled = selected === index}
{@const label = skinTones.get(index)}
<button
class="hulyPopup-row withKeys"
{disabled}
on:click={() => {
if (disabled) return undefined
dispatch('close', index)
}}
>
<span style:font-size={'1.5rem'}>{skin}</span>
{#if label}<span class="hulyPopup-row__label"><Label {label} /></span>{/if}
{#if disabled}<span class="hulyPopup-row__keys"><ModernCheckbox checked disabled /></span>{/if}
</button>
{/each}
</div>
</div>
@@ -0,0 +1,36 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
import { createEventDispatcher } from 'svelte'
import type { Emoji } from 'emojibase'
import { generateSkinToneEmojis, getEmojiCode, type EmojiWithGroup } from '.'
import { ButtonBase, closeTooltip } from '../..'
export let emoji: number | number[] | string | Emoji | EmojiWithGroup
export let selected: number
const dispatch = createEventDispatcher()
const skins: string[] = generateSkinToneEmojis(getEmojiCode(emoji))
</script>
<div class="flex-row-center flex-gap-1">
{#each skins as skin, index}
{@const disabled = selected === index}
<ButtonBase
type={'type-button-icon'}
{disabled}
kind={disabled ? 'secondary' : 'tertiary'}
size={'small'}
on:click={() => {
if (disabled) return undefined
dispatch('update', index)
closeTooltip()
}}
>
<span style:font-size={'1.5rem'}>{skin}</span>
</ButtonBase>
{/each}
</div>
@@ -0,0 +1,20 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M12,7.8c0.4,0,0.8-0.3,0.8-0.8S12.4,6.2,12,6.2c-3.2,0-5.8,2.6-5.8,5.8c0,3.2,2.6,5.8,5.8,5.8c3.2,0,5.8-2.6,5.8-5.8c0-0.4-0.3-0.8-0.8-0.8s-0.8,0.3-0.8,0.8c0,2.3-1.9,4.2-4.2,4.2c-2.3,0-4.2-1.9-4.2-4.2C7.8,9.7,9.7,7.8,12,7.8z"
/>
<path
d="M21.7,10.9c0-0.4-0.4-0.7-0.8-0.7c-0.4,0-0.7,0.4-0.7,0.8c0.1,0.6,0.1,1.2,0,1.8c-0.2,2.2-1.3,4.2-3.1,5.5c-1.7,1.4-3.9,2-6.1,1.8c-2.2-0.2-4.2-1.3-5.5-3.1c-1.4-1.7-2-3.9-1.8-6.1C4,8.9,5.1,6.9,6.8,5.6s3.9-2,6.1-1.8c0.4,0.1,0.8-0.2,0.8-0.7c0-0.4-0.2-0.8-0.7-0.8C10.5,2,7.9,2.8,5.9,4.4c-2,1.6-3.3,3.9-3.6,6.5C2,13.5,2.8,16,4.4,18.1c1.6,2,3.9,3.3,6.5,3.6c0.4,0,0.7,0.1,1.1,0.1c2.2,0,4.3-0.7,6.1-2.1c2-1.6,3.3-3.9,3.6-6.5C21.8,12.4,21.8,11.6,21.7,10.9z"
/>
<path
d="M12.6,10.4c-0.2-0.1-0.4-0.1-0.6-0.1c-1,0-1.8,0.8-1.8,1.8s0.8,1.8,1.8,1.8s1.8-0.8,1.8-1.8c0-0.2,0-0.4-0.1-0.6l1.7-1.7H18c0.2,0,0.4-0.1,0.5-0.2l3-3c0.2-0.2,0.3-0.5,0.2-0.8c-0.1-0.3-0.4-0.5-0.7-0.5h-2.2V3c0-0.3-0.2-0.6-0.5-0.7c-0.3-0.1-0.6-0.1-0.8,0.2l-3,3c-0.1,0.1-0.2,0.3-0.2,0.5v2.7L12.6,10.4z M15.8,6.3l1.5-1.5V6c0,0.4,0.3,0.8,0.8,0.8h1.2l-1.5,1.5h-1.9V6.3z"
/>
</svg>
@@ -0,0 +1,16 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path d="M10,9.8c-0.7,0-1.2,0.6-1.2,1.3s0.6,1.2,1.2,1.2s1.2-0.6,1.2-1.2v0C11.2,10.3,10.7,9.8,10,9.8z" />
<path d="M14,9.8c-0.7,0-1.2,0.6-1.2,1.3s0.6,1.2,1.2,1.2s1.2-0.6,1.2-1.2v0C15.2,10.3,14.7,9.8,14,9.8z" />
<path
d="M21.7,10.6l-2-6.8c-0.1-0.4-0.5-0.6-0.8-0.5l-6,1c0,0,0,0,0,0h-1.7c0,0,0,0,0,0l-6-1C4.7,3.2,4.4,3.4,4.3,3.8l-2,6.9c-0.1,0.6,0.1,1.3,0.6,1.7c0.3,0.3,0.7,0.4,1.1,0.4c0.1,0,0.2,0,0.3,0c0.8,5.3,2.7,8,5.7,8h4c3,0,4.9-2.7,5.7-8c0.1,0,0.2,0,0.3,0c0.4,0,0.8-0.1,1.1-0.4C21.6,11.9,21.9,11.3,21.7,10.6z M3.8,11.2c-0.1,0-0.1-0.1-0.1-0.2l1.8-6.2l4,0.6l-5.3,5.7C4.1,11.3,3.9,11.3,3.8,11.2z M14,19.2h-1.2V18c0-0.1,0-0.2-0.1-0.4c0.7-0.2,1.1-0.8,1.1-1.6c0-0.4-0.3-0.8-0.8-0.8h-2c-0.4,0-0.8,0.3-0.8,0.8c0,0.8,0.4,1.4,1.1,1.6c-0.1,0.1-0.1,0.2-0.1,0.4v1.2H10c-2.2,0-3.6-2.5-4.3-7.3c0-0.1,0-0.1,0-0.1l5.6-6h1.4l5.6,6c0,0,0,0.1,0,0.1C17.6,16.8,16.2,19.2,14,19.2z M20.2,11.2c-0.1,0.1-0.3,0.1-0.4,0l-5.3-5.7l4-0.6l1.8,6.1C20.3,11.1,20.2,11.1,20.2,11.2z"
/>
</svg>
@@ -0,0 +1,14 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M19.3,4.3c-0.3-0.1-0.6-0.1-0.8,0.2c-1.6,1.6-4.3,1.6-5.9,0c-2.2-2.2-5.8-2.2-8,0C4.3,4.6,4.2,4.8,4.2,5v9v7c0,0.4,0.3,0.8,0.8,0.8s0.8-0.3,0.8-0.8v-6.6c1.7-1.4,4.2-1.4,5.7,0.2c1.1,1.1,2.6,1.6,4,1.6s2.9-0.5,4-1.6c0.1-0.1,0.2-0.3,0.2-0.5V5C19.8,4.7,19.6,4.4,19.3,4.3z M18.2,13.7c-1.7,1.4-4.2,1.3-5.7-0.2c-1.1-1.1-2.6-1.6-4-1.6c-0.9,0-1.9,0.2-2.8,0.7V5.3C7.4,3.9,9.9,4,11.5,5.5c1.8,1.8,4.6,2.1,6.8,0.9V13.7z"
/>
</svg>
@@ -0,0 +1,20 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M7.6,7.6C7.7,7.7,7.8,7.8,8,7.8c0.2,0,0.5-0.1,0.6-0.3c0.2-0.3,0.2-0.8-0.2-1C8,6.1,7.7,5.6,7.8,5c0-0.5,0.2-1.1,0.7-1.4c0.3-0.2,0.4-0.7,0.2-1c-0.2-0.3-0.7-0.4-1-0.2C6.7,3,6.2,4,6.2,5C6.2,6,6.7,7,7.6,7.6z"
/>
<path
d="M11.6,7.6c0.1,0.1,0.3,0.1,0.4,0.1c0.2,0,0.5-0.1,0.6-0.3c0.2-0.3,0.2-0.8-0.2-1C12,6.1,11.7,5.6,11.8,5c0-0.5,0.2-1.1,0.7-1.4c0.3-0.2,0.4-0.7,0.2-1c-0.2-0.3-0.7-0.4-1-0.2C10.7,3,10.2,4,10.2,5C10.2,6,10.7,7,11.6,7.6z"
/>
<path
d="M19.6,10.6c-0.6-0.3-1.2-0.4-1.8-0.3V10c0-0.4-0.3-0.8-0.8-0.8H3c-0.4,0-0.8,0.3-0.8,0.8v5c0,3.7,3,6.8,6.8,6.8h2c2.8,0,5.2-1.7,6.2-4.1c0.3,0.1,0.5,0.1,0.8,0.1c0.4,0,0.9-0.1,1.3-0.2c0.9-0.3,1.7-1,2.1-2C22.3,13.7,21.4,11.5,19.6,10.6zM16.2,10.8v0.4c0,0,0,0,0,0v1.6c-0.8-0.3-1.7-0.5-2.7-0.5c-1.5,0-3,0.4-4,1.2c-0.7,0.5-1.8,0.8-3.1,0.8c-1.1,0-2-0.2-2.7-0.7v-2.8H16.2z M11,20.2H9c-2.8,0-5.1-2.2-5.2-5c0.8,0.3,1.7,0.5,2.6,0.5c0.1,0,0.1,0,0.2,0c1.5,0,2.9-0.4,3.9-1.2c0.7-0.5,1.8-0.8,3-0.8c0.1,0,0.1,0,0.2,0c1,0,2,0.2,2.7,0.7V15C16.2,17.9,13.9,20.2,11,20.2z M20,14.9c-0.2,0.5-0.7,1-1.3,1.2c-0.4,0.1-0.8,0.2-1.1,0.1c0.1-0.4,0.1-0.8,0.1-1.2v-3.2c0.4,0,0.8,0,1.2,0.2C20.1,12.5,20.6,13.8,20,14.9z"
/>
</svg>
@@ -0,0 +1,17 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M12,7.2c-0.4,0-0.8,0.3-0.8,0.8v4c0,0.2,0.1,0.4,0.2,0.5l2,2c0.1,0.1,0.3,0.2,0.5,0.2s0.4-0.1,0.5-0.2c0.3-0.3,0.3-0.8,0-1.1l-1.8-1.8V8C12.8,7.6,12.4,7.2,12,7.2z"
/>
<path
d="M19.6,5.8c-1.6-2-4-3.3-6.6-3.5C7.6,1.7,2.8,5.6,2.3,10.9c0,0.4,0.3,0.8,0.7,0.8c0.4,0,0.8-0.3,0.8-0.7c0.5-4.5,4.5-7.8,9-7.4C15,3.9,17,5,18.4,6.7c1.4,1.7,2,3.9,1.8,6c-0.2,2.2-1.3,4.2-3,5.6c-1.7,1.4-3.9,2-6,1.8c-2.8-0.3-5.2-2-6.5-4.4H8c0.4,0,0.8-0.3,0.8-0.8S8.5,14.2,8,14.2H3.6c0,0,0,0,0,0H3c-0.4,0-0.8,0.3-0.8,0.8v5c0,0.4,0.3,0.8,0.8,0.8s0.8-0.3,0.8-0.8v-2.8c1.6,2.5,4.2,4.1,7.2,4.4c0.3,0,0.7,0.1,1,0.1c2.2,0,4.4-0.8,6.1-2.2c2-1.6,3.3-4,3.5-6.6C22,10.3,21.2,7.8,19.6,5.8z"
/>
</svg>
@@ -0,0 +1,14 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M11,21.8c-0.1,0-0.2,0-0.2,0c-0.3-0.1-0.5-0.4-0.5-0.7v-6.2H5c-0.3,0-0.5-0.2-0.7-0.4c-0.1-0.3-0.1-0.6,0.1-0.8l8-11c0.2-0.3,0.5-0.4,0.8-0.3c0.3,0.1,0.5,0.4,0.5,0.7v6.2H19c0.3,0,0.5,0.2,0.7,0.4s0.1,0.6-0.1,0.8l-8,11C11.5,21.6,11.2,21.8,11,21.8z M6.5,13.2H11c0.4,0,0.8,0.3,0.8,0.8v4.7l5.8-7.9H13c-0.4,0-0.8-0.3-0.8-0.8V5.3L6.5,13.2z"
/>
</svg>
@@ -0,0 +1,15 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M20.7,6.9l-3.6-3.6c-1.4-1.4-3.7-1.4-5.1,0L9.3,6C8.6,6.6,8.2,7.6,8.2,8.5c0,0.9,0.3,1.7,0.8,2.3l-1.6,1.6c-0.1,0.1-0.2,0.3-0.2,0.5v1.2H6c-0.4,0-0.8,0.3-0.8,0.8v1.2H4c-0.2,0-0.4,0.1-0.5,0.2l-0.6,0.6c-0.4,0.5-0.6,1.1-0.6,1.8l0,1.2l0,0.2c0.1,0.9,0.9,1.5,1.7,1.5l1.2,0l0.2,0c0.6-0.1,1.2-0.3,1.7-0.8l6-6c1.4,1.2,3.6,1.1,4.9-0.2l2.6-2.6C22.1,10.6,22.1,8.3,20.7,6.9z M19.6,11L17,13.6c-0.8,0.8-2.2,0.8-3,0l-0.3-0.3c-0.3-0.3-0.8-0.3-1.1,0l-6.6,6.6c-0.2,0.2-0.5,0.3-0.7,0.4l-1.3,0c-0.1,0-0.2-0.1-0.2-0.2l0-1.2c0-0.3,0.1-0.6,0.3-0.8l0.3-0.3H6c0.4,0,0.8-0.3,0.8-0.8v-1.2H8c0.4,0,0.8-0.3,0.8-0.8v-1.7l1.9-1.9c0.1-0.1,0.2-0.3,0.2-0.5c0-0.2-0.1-0.4-0.2-0.5L10.4,10c-0.8-0.8-0.8-2.2,0-3L13,4.4c0.8-0.8,2.2-0.8,3,0L19.6,8C20.5,8.8,20.5,10.2,19.6,11z"
/>
<path d="M15,7.8L15,7.8c-0.7,0-1.3,0.6-1.3,1.2s0.6,1.2,1.3,1.2s1.2-0.6,1.2-1.2S15.7,7.8,15,7.8z" />
</svg>
@@ -0,0 +1,14 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M21.5,20.5L16,14.9c1.1-1.3,1.8-3.1,1.8-4.9c0-4.3-3.5-7.8-7.8-7.8S2.2,5.7,2.2,10s3.5,7.8,7.8,7.8c1.9,0,3.6-0.7,4.9-1.8l5.5,5.5c0.1,0.1,0.3,0.2,0.5,0.2s0.4-0.1,0.5-0.2C21.8,21.2,21.8,20.8,21.5,20.5z M3.8,10c0-3.4,2.8-6.2,6.2-6.2s6.2,2.8,6.2,6.2s-2.8,6.2-6.2,6.2S3.8,13.4,3.8,10z"
/>
</svg>
@@ -0,0 +1,23 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M12,2.2c-5.4,0-9.8,4.4-9.8,9.8s4.4,9.8,9.8,9.8s9.8-4.4,9.8-9.8S17.4,2.2,12,2.2z M12,20.2c-4.5,0-8.2-3.7-8.2-8.2S7.5,3.8,12,3.8s8.2,3.7,8.2,8.2S16.5,20.2,12,20.2z"
/>
<path
d="M7.8,9.5c0,0.1,0.1,0.1,0.1,0.2c0,0.1,0.1,0.1,0.2,0.2c0.2,0.2,0.6,0.4,0.9,0.4c0.1,0,0.2,0,0.2,0c0.1,0,0.1,0,0.2-0.1c0.1,0,0.1-0.1,0.2-0.1c0.1,0,0.1-0.1,0.2-0.2C9.9,9.8,10,9.8,10,9.7c0-0.1,0.1-0.1,0.1-0.2c0-0.1,0.1-0.2,0.1-0.2c0-0.1,0-0.2,0-0.2c0-0.3-0.1-0.7-0.4-0.9C9.8,8.1,9.8,8,9.7,8c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.2-0.1-0.2-0.1c-0.4-0.1-0.8,0-1.1,0.3C7.9,8.3,7.8,8.7,7.8,9c0,0.1,0,0.2,0,0.2C7.8,9.3,7.8,9.4,7.8,9.5z"
/>
<path
d="M14.3,10c0.1,0,0.1,0.1,0.2,0.1c0.1,0,0.2,0.1,0.2,0.1c0.1,0,0.2,0,0.2,0s0.2,0,0.2,0c0.1,0,0.2,0,0.2-0.1c0.1,0,0.2-0.1,0.2-0.1c0.1-0.1,0.1-0.1,0.2-0.2c0.2-0.2,0.4-0.6,0.4-0.9c0-0.3-0.1-0.7-0.4-0.9c0-0.1-0.1-0.1-0.2-0.2c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.2-0.1-0.2-0.1c-0.2,0-0.3,0-0.5,0c-0.1,0-0.2,0-0.2,0.1c-0.1,0-0.1,0.1-0.2,0.1c-0.1,0-0.1,0.1-0.2,0.2c-0.2,0.2-0.4,0.6-0.4,0.9c0,0.3,0.1,0.6,0.4,0.9C14.2,9.9,14.2,10,14.3,10z"
/>
<path
d="M16,12.2H8c-0.4,0-0.8,0.3-0.8,0.8c0,2.6,2.1,4.8,4.8,4.8s4.8-2.1,4.8-4.8C16.8,12.6,16.4,12.2,16,12.2z M12,16.2c-1.5,0-2.8-1.1-3.2-2.5h6.3C14.8,15.2,13.5,16.2,12,16.2z"
/>
</svg>
@@ -0,0 +1,23 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M6.5,10.8c2.3,0,4.2-1.9,4.2-4.2S8.8,2.2,6.5,2.2S2.2,4.2,2.2,6.5S4.2,10.8,6.5,10.8z M6.5,3.8C8,3.8,9.2,5,9.2,6.5S8,9.2,6.5,9.2S3.8,8,3.8,6.5S5,3.8,6.5,3.8z"
/>
<path
d="M7.2,13.6c-0.3-0.5-1-0.5-1.3,0l-4,7c-0.1,0.2-0.1,0.5,0,0.7c0.1,0.2,0.4,0.4,0.6,0.4h8c0.3,0,0.5-0.1,0.6-0.4c0.1-0.2,0.1-0.5,0-0.7L7.2,13.6z M3.8,20.2l2.7-4.7l2.7,4.7H3.8z"
/>
<path
d="M18.6,6.5l3-3c0.3-0.3,0.3-0.8,0-1.1s-0.8-0.3-1.1,0l-3,3l-3-3c-0.3-0.3-0.8-0.3-1.1,0s-0.3,0.8,0,1.1l3,3l-3,3c-0.3,0.3-0.3,0.8,0,1.1c0.1,0.1,0.3,0.2,0.5,0.2s0.4-0.1,0.5-0.2l3-3l3,3c0.1,0.1,0.3,0.2,0.5,0.2s0.4-0.1,0.5-0.2c0.3-0.3,0.3-0.8,0-1.1L18.6,6.5z"
/>
<path
d="M21,13.2h-7c-0.4,0-0.8,0.3-0.8,0.8v7c0,0.4,0.3,0.8,0.8,0.8h7c0.4,0,0.8-0.3,0.8-0.8v-7C21.8,13.6,21.4,13.2,21,13.2zM20.2,20.2h-5.5v-5.5h5.5V20.2z"
/>
</svg>
@@ -0,0 +1,17 @@
<script lang="ts">
//
// © 2025 Hardcore Engineering, Inc. All Rights Reserved.
// Licensed under the Eclipse Public License v2.0 (SPDX: EPL-2.0).
//
export let size: 'small' | 'medium' | 'large' | 'x-large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" {fill} xmlns="http://www.w3.org/2000/svg">
<path
d="M21.5,11.5l-9-9c-0.3-0.3-0.8-0.3-1.1,0l-9,9c-0.2,0.2-0.3,0.5-0.2,0.8s0.4,0.5,0.7,0.5h1.2V19c0,1.5,1.2,2.8,2.8,2.8h10c1.5,0,2.8-1.2,2.8-2.8v-6.2H21c0.3,0,0.6-0.2,0.7-0.5C21.8,12,21.7,11.7,21.5,11.5z M18.2,19c0,0.7-0.6,1.2-1.2,1.2H7c-0.7,0-1.2-0.6-1.2-1.2v-7c0-0.4-0.3-0.8-0.8-0.8H4.8L12,4.1l7.2,7.2H19c-0.4,0-0.8,0.3-0.8,0.8V19z"
/>
<path
d="M14,11.2h-4c-0.4,0-0.8,0.3-0.8,0.8v4c0,0.4,0.3,0.8,0.8,0.8h4c0.4,0,0.8-0.3,0.8-0.8v-4C14.8,11.6,14.4,11.2,14,11.2zM13.2,15.2h-2.5v-2.5h2.5V15.2z"
/>
</svg>
+97
View File
@@ -0,0 +1,97 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { IntlString } from '@hcengineering/platform'
import IconFrequentlyUsed from './icons/FrequentlyUsed.svelte'
import IconGettingWorkDone from './icons/GettingWorkDone.svelte'
import IconSmileysAndPeople from './icons/SmileysAndPeople.svelte'
import IconAnimalsAndNature from './icons/AnimalsAndNature.svelte'
import IconFoodAndDrink from './icons/FoodAndDrink.svelte'
import IconTravelAndPlaces from './icons/TravelAndPlaces.svelte'
import IconActivities from './icons/Activities.svelte'
import IconObjects from './icons/Objects.svelte'
import IconSymbols from './icons/Symbols.svelte'
import IconFlags from './icons/Flags.svelte'
import plugin from '../../plugin'
import type { EmojiCategory } from './types'
export * from './types'
export * from './store'
export * from './utils'
export { default as EmojiPopup } from './EmojiPopup.svelte'
export { default as EmojiButton } from './EmojiButton.svelte'
export const emojiCategories: EmojiCategory[] = [
{ id: 'frequently-used', label: plugin.string.FrequentlyUsed, icon: IconFrequentlyUsed },
{
id: 'getting-work-done',
label: plugin.string.GettingWorkDone,
icon: IconGettingWorkDone,
emojisString: [
'2705',
'1F440',
'1F64C',
'1F64F',
'2795',
'2796',
'1F44F',
'1F4A1',
'1F3AF',
'1F44B',
'1F44D',
'1F389',
'0031-FE0F-20E3',
'0032-FE0F-20E3',
'0033-FE0F-20E3',
'1F4E3',
'26AA',
'1F535',
'1F534',
'1F3CE'
]
},
{
id: 'smileys-people',
label: plugin.string.SmileysAndPeople,
icon: IconSmileysAndPeople,
categories: ['smileys-emotion', 'people-body']
},
{
id: 'animals-nature',
label: plugin.string.AnimalsAndNature,
icon: IconAnimalsAndNature,
categories: 'animals-nature'
},
{ id: 'food-drink', label: plugin.string.FoodAndDrink, icon: IconFoodAndDrink, categories: 'food-drink' },
{ id: 'travel-places', label: plugin.string.TravelAndPlaces, icon: IconTravelAndPlaces, categories: 'travel-places' },
{ id: 'activities', label: plugin.string.Activities, icon: IconActivities, categories: 'activities' },
{ id: 'objects', label: plugin.string.Objects, icon: IconObjects, categories: 'objects' },
{ id: 'symbols', label: plugin.string.Symbols, icon: IconSymbols, categories: 'symbols' },
{ id: 'flags', label: plugin.string.Flags, icon: IconFlags, categories: 'flags' }
]
export const skinTonesCodes = [0x1f3fb, 0x1f3fc, 0x1f3fd, 0x1f3fe, 0x1f3ff]
export const skinTones: Map<number, IntlString> = new Map<number, IntlString>(
[
plugin.string.NoTone,
plugin.string.Light,
plugin.string.MediumLight,
plugin.string.Medium,
plugin.string.MediumDark,
plugin.string.Dark
].map((label, index) => [index, label])
)
+44
View File
@@ -0,0 +1,44 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import { writable, derived } from 'svelte/store'
import type { Emoji } from 'emojibase'
import type { EmojiWithGroup } from '.'
export const emojiStore = writable<EmojiWithGroup[]>([])
export const emojiComponents = writable<Emoji[]>([])
export const searchEmoji = writable<string>('')
export const resultEmojis = derived([emojiStore, searchEmoji], ([emojis, search]) => {
return search !== ''
? emojis.filter(
(emoji) =>
(emoji.tags?.some((tag: string) => tag.toLowerCase().startsWith(search.toLowerCase())) ?? false) ||
emoji.label.toLowerCase().includes(search.toLowerCase())
)
: emojis
})
export const groupsResultEmojis = derived(resultEmojis, (result) => {
const keys = new Set(result.map((res) => res?.key ?? ''))
const groups: string[] = keys?.size > 0 ? [...keys] : ['']
return {
emojis: new Map<string, EmojiWithGroup[]>(
groups.map((group) => {
return [group, result.filter((res) => res.key === group)]
})
),
groups
}
})
+33
View File
@@ -0,0 +1,33 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { IntlString } from '@hcengineering/platform'
import type { AnySvelteComponent } from '../..'
import type { Emoji } from 'emojibase'
export type EmojiWithGroup = Emoji & { key: string }
export interface EmojiCategory {
id: string
label: IntlString
icon: AnySvelteComponent
categories?: string[] | string
emojisString?: string[]
emojis?: EmojiWithGroup[]
}
export interface EmojiHierarchy {
emoji: EmojiWithGroup
parent?: EmojiWithGroup
}
+177
View File
@@ -0,0 +1,177 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import { get } from 'svelte/store'
import { fetchEmojis, fetchMessages } from 'emojibase'
import type { Emoji, Locale } from 'emojibase'
import { getCurrentAccount } from '@hcengineering/core'
import { deviceOptionsStore as deviceInfo } from '../..'
import { emojiStore, emojiComponents, emojiCategories, skinTonesCodes } from '.'
import type { EmojiWithGroup, EmojiHierarchy } from '.'
export async function loadEmojis (lang?: string): Promise<{
emojis: EmojiWithGroup[]
components: Emoji[]
}> {
const local = lang ?? get(deviceInfo).language ?? 'en'
const englishEmojis =
local === 'en'
? await fetchEmojis('en', { version: '15.0' })
: await fetchEmojis('en', { compact: true, version: '15.0' })
const languageEmojis = local === 'en' ? null : await fetchEmojis(local as Locale, { version: '15.0' })
const messages = await fetchMessages(local as Locale)
const groups = messages.groups
const groupKeys = new Map<number, string>(groups.map((group, index) => [index, group.key]))
const categories = new Map<string, string>()
emojiCategories.forEach((cat) => {
if (Array.isArray(cat.categories)) cat.categories.forEach((c) => categories.set(c, cat.id))
else if (typeof cat.categories === 'string') categories.set(cat.categories, cat.id)
})
const emojis =
languageEmojis !== null
? languageEmojis.map((langEmoji, index) => {
return {
...langEmoji,
tags: [...(englishEmojis[index]?.tags ?? []), ...(langEmoji?.tags ?? [])]
}
})
: (englishEmojis as Emoji[])
return {
emojis: emojis
.filter((e) => e.group !== 2 && e.group !== undefined)
.map((e) => {
return { ...e, key: categories.get(groupKeys.get(e?.group ?? 0) ?? '') ?? '' }
}),
components: emojis.filter((e) => e.group === 2)
}
}
export async function updateEmojis (lang?: string): Promise<void> {
const { emojis, components } = await loadEmojis(lang)
emojiStore.set(emojis)
emojiComponents.set(components)
}
function getEmojisLocalStorageKey (suffix: string = 'frequently'): string {
const me = getCurrentAccount()
return `emojis.${suffix}.${me.uuid}`
}
export const removeFrequentlyEmojis = (_hexcode: string): void => {
const emoji = getEmoji(_hexcode)
const hexcode = emoji?.parent?.hexcode ?? emoji?.emoji.hexcode
if (hexcode === undefined) return
const frequentlyEmojisKey = getEmojisLocalStorageKey()
const frequentlyEmojis = window.localStorage.getItem(frequentlyEmojisKey)
if (frequentlyEmojis != null) {
const parsedEmojis = JSON.parse(frequentlyEmojis)
if (Array.isArray(parsedEmojis)) {
window.localStorage.setItem(
frequentlyEmojisKey,
JSON.stringify(parsedEmojis.filter((pe) => pe.hexcode !== hexcode))
)
}
}
}
export const addFrequentlyEmojis = (_hexcode: string): void => {
const emoji = getEmoji(_hexcode)
const hexcode = emoji?.parent?.hexcode ?? emoji?.emoji.hexcode
if (hexcode === undefined) return
const frequentlyEmojisKey = getEmojisLocalStorageKey()
const frequentlyEmojis = window.localStorage.getItem(frequentlyEmojisKey)
const empty = frequentlyEmojis == null
if (!empty) {
const parsedEmojis = JSON.parse(frequentlyEmojis)
if (Array.isArray(parsedEmojis)) {
const index = parsedEmojis.findIndex((pe) => pe.hexcode === hexcode)
if (index === -1) parsedEmojis.push({ hexcode, count: 1 })
else parsedEmojis[index].count++
parsedEmojis.sort((a, b) => b.count - a.count)
window.localStorage.setItem(frequentlyEmojisKey, JSON.stringify(parsedEmojis))
return undefined
}
}
window.localStorage.setItem(frequentlyEmojisKey, JSON.stringify([{ hexcode, count: 1 }]))
}
export const getFrequentlyEmojis = (): EmojiWithGroup[] | undefined => {
const frequentlyEmojisKey = getEmojisLocalStorageKey()
const frequentlyEmojis = window.localStorage.getItem(frequentlyEmojisKey)
if (frequentlyEmojis == null) return undefined
try {
const parsedEmojis = JSON.parse(frequentlyEmojis)
if (!Array.isArray(parsedEmojis)) return undefined
return parsedEmojis
.map((pe) => {
const map = getEmoji(pe.hexcode)
return map?.parent ?? map?.emoji
})
.filter((f) => f !== undefined) as EmojiWithGroup[]
} catch (e) {
console.error(e)
return undefined
}
}
export const setSkinTone = (skinTone: number): void => {
const skinToneKey = getEmojisLocalStorageKey('skinTone')
window.localStorage.setItem(skinToneKey, JSON.stringify(skinTone))
}
export const getSkinTone = (): number => {
const skinToneKey = getEmojisLocalStorageKey('skinTone')
const skinTone = window.localStorage.getItem(skinToneKey)
if (skinTone == null) return 0
try {
return JSON.parse(skinTone)
} catch (e) {
console.error(e)
return 0
}
}
export const generateSkinToneEmojis = (baseEmoji: number | number[]): string[] => {
const isArray = Array.isArray(baseEmoji)
return [
String.fromCodePoint(...(isArray ? baseEmoji : [baseEmoji])),
...skinTonesCodes.map((skinTone) => {
return String.fromCodePoint(...(isArray ? baseEmoji : [baseEmoji]), skinTone)
})
]
}
export const getEmojiMap = (): Map<string, EmojiHierarchy> | undefined => {
const result = new Map<string, EmojiHierarchy>()
const emojis = get(emojiStore)
emojis.forEach((emoji) => {
result.set(emoji.hexcode, { emoji })
emoji.skins?.forEach((skin) => result.set(skin.hexcode, { emoji: { ...skin, key: emoji.key }, parent: emoji }))
})
return result
}
export const getEmoji = (hexcode: string): EmojiHierarchy | undefined => {
return getEmojiMap()?.get(hexcode)
}
export const getEmojiCode = (e: number | number[] | string | Emoji | EmojiWithGroup): number | number[] => {
return typeof e === 'number' || Array.isArray(e)
? e
: (typeof e === 'object' ? e.hexcode : e).split('-').map((h) => parseInt(h, 16))
}
@@ -1,20 +0,0 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let opacity: string = '1'
</script>
<svg class="svg-{size}" fill="none" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<g {opacity}>
<path d="M7.5 17.5H12.5" stroke="currentColor" stroke-linecap="round" />
<path d="M10 17.5V14.1667" stroke="currentColor" stroke-linecap="round" />
<path
d="M4.6665 7.7381C4.6665 7.66499 4.6667 7.64911 4.66729 7.63863C4.68156 7.38455 4.88439 7.18172 5.13847 7.16745C5.14894 7.16687 5.16482 7.16667 5.23793 7.16667H14.7617C14.8349 7.16667 14.8507 7.16687 14.8612 7.16745C15.1153 7.18172 15.3181 7.38455 15.3324 7.63863C15.333 7.64911 15.3332 7.66498 15.3332 7.7381V8.33333C15.3332 11.2789 12.9454 13.6667 9.99984 13.6667C7.05432 13.6667 4.6665 11.2789 4.6665 8.33333V7.7381Z"
stroke="currentColor"
stroke-linecap="round"
/>
<path
d="M9.51924 9.86264C9.44338 10.1282 9.59712 10.4049 9.86264 10.4808C10.1282 10.5566 10.4049 10.4029 10.4808 10.1374L9.51924 9.86264ZM11.3972 5.10987L10.9164 4.9725L11.3972 5.10987ZM12.5774 3.80235L12.7631 4.26659H12.7631L12.5774 3.80235ZM11.7511 4.24292L11.38 3.90789L11.7511 4.24292ZM10.4808 10.1374L11.8779 5.24723L10.9164 4.9725L9.51924 9.86264L10.4808 10.1374ZM12.7631 4.26659L16.019 2.96424L15.6476 2.03576L12.3918 3.33812L12.7631 4.26659ZM11.8779 5.24723C12.0238 4.73685 12.0628 4.64387 12.1223 4.57796L11.38 3.90789C11.1285 4.18646 11.0352 4.55661 10.9164 4.9725L11.8779 5.24723ZM12.3918 3.33812C11.9902 3.49876 11.6314 3.62933 11.38 3.90789L12.1223 4.57796C12.1818 4.51204 12.2703 4.46373 12.7631 4.26659L12.3918 3.33812Z"
stroke="currentColor"
/>
</g>
</svg>
@@ -1,18 +0,0 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let opacity: string = '1'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g {opacity}>
<path
d="M12.0448 9.07344L12.5026 8.87234L12.0448 9.07344ZM7.49167 16.6515L7.52884 17.1501L7.49167 16.6515ZM7.45449 16.1529C7.332 16.162 7.20817 16.1667 7.08317 16.1667V17.1667C7.23301 17.1667 7.38164 17.1611 7.52884 17.1501L7.45449 16.1529ZM7.08317 16.1667C4.36777 16.1667 2.1665 13.9654 2.1665 11.25H1.1665C1.1665 14.5177 3.81549 17.1667 7.08317 17.1667V16.1667ZM2.1665 11.25C2.1665 8.5346 4.36777 6.33333 7.08317 6.33333V5.33333C3.81549 5.33333 1.1665 7.98231 1.1665 11.25H2.1665ZM7.08317 6.33333C9.09506 6.33333 10.8258 7.54181 11.587 9.27454L12.5026 8.87234C11.5876 6.78951 9.50597 5.33333 7.08317 5.33333V6.33333ZM13.3332 10.5C14.898 10.5 16.1665 11.7685 16.1665 13.3333H17.1665C17.1665 11.2162 15.4503 9.5 13.3332 9.5V10.5ZM16.1665 13.3333C16.1665 14.8981 14.898 16.1667 13.3332 16.1667V17.1667C15.4503 17.1667 17.1665 15.4504 17.1665 13.3333H16.1665ZM13.3332 16.1667H7.50743V17.1667H13.3332V16.1667ZM7.50743 16.1667C7.77939 16.1667 7.99984 16.3871 7.99984 16.6591H6.99984C6.99984 16.9394 7.22708 17.1667 7.50743 17.1667V16.1667ZM11.587 9.27454C11.8757 9.93169 12.5127 10.5 13.3332 10.5V9.5C13.0071 9.5 12.675 9.26494 12.5026 8.87234L11.587 9.27454ZM7.52884 17.1501C7.24371 17.1714 6.99984 16.9459 6.99984 16.6591H7.99984C7.99984 16.3634 7.74844 16.131 7.45449 16.1529L7.52884 17.1501Z"
{fill}
/>
<path
d="M16.2794 11.2796C16.6988 10.8602 17.0239 10.3561 17.2328 9.80104C17.4417 9.24595 17.5297 8.65266 17.4909 8.06082C17.4521 7.46899 17.2874 6.89225 17.0078 6.36918C16.7283 5.84611 16.3402 5.38876 15.8697 5.0277C15.3991 4.66664 14.8569 4.41019 14.2793 4.27551C13.7017 4.14083 13.102 4.13102 12.5203 4.24673C11.9386 4.36244 11.3883 4.601 10.9062 4.94647C10.4241 5.29194 10.0213 5.73636 9.72473 6.25"
stroke="currentColor"
/>
</g>
</svg>
@@ -1,12 +0,0 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let opacity: string = '1'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path
{opacity}
d="M9.50963 17.0277L9.44387 17.5234L9.50963 17.0277ZM8.62785 16.7027L8.27419 17.0562L8.62785 16.7027ZM6.92392 12.2754L6.61606 12.6694L6.92392 12.2754ZM7.65746 13.164L7.19335 13.3501L7.65746 13.164ZM7.44487 12.7262L7.84461 12.4258L7.44487 12.7262ZM10.4904 17.0277L10.5561 17.5234L10.4904 17.0277ZM11.3722 16.7027L11.7258 17.0562L11.3722 16.7027ZM13.0761 12.2754L12.7682 11.8814L13.0761 12.2754ZM12.5551 12.7262L12.9549 13.0265L12.5551 12.7262ZM14.5 8.33333C14.5 9.77433 13.8232 11.057 12.7682 11.8814L13.3839 12.6694C14.6711 11.6636 15.5 10.0951 15.5 8.33333H14.5ZM10 3.83333C12.4853 3.83333 14.5 5.84805 14.5 8.33333H15.5C15.5 5.29577 13.0376 2.83333 10 2.83333V3.83333ZM5.5 8.33333C5.5 5.84805 7.51472 3.83333 10 3.83333V2.83333C6.96243 2.83333 4.5 5.29577 4.5 8.33333H5.5ZM7.23179 11.8814C6.17675 11.057 5.5 9.77433 5.5 8.33333H4.5C4.5 10.0951 5.32894 11.6636 6.61606 12.6694L7.23179 11.8814ZM8.748 15.3687C8.63971 14.5487 8.42923 13.7455 8.12156 12.978L7.19335 13.3501C7.46999 14.0402 7.65924 14.7623 7.75661 15.4996L8.748 15.3687ZM10.4246 16.5321C10.1428 16.5695 9.85719 16.5695 9.57538 16.5321L9.44387 17.5234C9.81297 17.5724 10.187 17.5724 10.5561 17.5234L10.4246 16.5321ZM11.8784 12.978C11.5708 13.7455 11.3603 14.5487 11.252 15.3687L12.2434 15.4996C12.3408 14.7623 12.53 14.0402 12.8066 13.3501L11.8784 12.978ZM7.75661 15.4996C7.80026 15.8302 7.8381 16.1235 7.90038 16.362C7.96682 16.6164 8.07123 16.8531 8.27419 17.0562L8.98151 16.3493C8.94478 16.3125 8.90671 16.2578 8.86794 16.1093C8.82501 15.945 8.79492 15.7239 8.748 15.3687L7.75661 15.4996ZM9.57538 16.5321C9.34646 16.5017 9.23632 16.4853 9.15156 16.458C9.09245 16.4389 9.04706 16.4149 8.98151 16.3493L8.27419 17.0562C8.6486 17.4308 9.03105 17.4686 9.44387 17.5234L9.57538 16.5321ZM6.61606 12.6694C6.76644 12.7869 6.86761 12.8661 6.94183 12.9289C7.01729 12.9928 7.0396 13.0192 7.04512 13.0265L7.84461 12.4258C7.77064 12.3274 7.67964 12.2433 7.58807 12.1658C7.49527 12.0872 7.37571 11.9939 7.23179 11.8814L6.61606 12.6694ZM8.12156 12.978C8.04043 12.7756 7.97211 12.5955 7.84461 12.4258L7.04512 13.0265C7.07659 13.0684 7.09701 13.1097 7.19335 13.3501L8.12156 12.978ZM10.5561 17.5234C10.969 17.4686 11.3514 17.4308 11.7258 17.0562L11.0185 16.3493C10.9529 16.4149 10.9076 16.4389 10.8484 16.458C10.7637 16.4853 10.6535 16.5017 10.4246 16.5321L10.5561 17.5234ZM11.252 15.3687C11.2051 15.7239 11.175 15.945 11.1321 16.1093C11.0933 16.2578 11.0552 16.3125 11.0185 16.3493L11.7258 17.0562C11.9288 16.8531 12.0332 16.6164 12.0996 16.362C12.1619 16.1235 12.1997 15.8302 12.2434 15.4996L11.252 15.3687ZM12.7682 11.8814C12.6243 11.9939 12.5047 12.0872 12.4119 12.1658C12.3204 12.2433 12.2294 12.3274 12.1554 12.4258L12.9549 13.0265C12.9604 13.0192 12.9827 12.9928 13.0582 12.9289C13.1324 12.8661 13.2336 12.7869 13.3839 12.6694L12.7682 11.8814ZM12.8066 13.3501C12.903 13.1097 12.9234 13.0684 12.9549 13.0265L12.1554 12.4258C12.0279 12.5955 11.9596 12.7756 11.8784 12.978L12.8066 13.3501Z"
/>
</svg>
@@ -1,28 +0,0 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let opacity: string = '1'
</script>
<svg class="svg-{size}" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g {opacity}>
<path
d="M2 12.0261C2 17.1723 5.86713 21.413 10.8468 21.9863C11.5816 22.0709 12.2938 21.7576 12.8168 21.2333C13.4703 20.5781 13.4703 19.5159 12.8168 18.8607C12.2938 18.3364 11.8674 17.5541 12.2619 16.9268C13.8385 14.4192 22 20.178 22 12.0261C22 6.48884 17.5228 2 12 2C6.47715 2 2 6.48884 2 12.0261Z"
stroke="#1C274C"
stroke-width="1.5"
/><circle cx="17.5" cy="11.5" r="0.75" stroke="#1C274C" stroke-width="1.5" /><circle
cx="6.5"
cy="11.5"
r="0.75"
stroke="#1C274C"
stroke-width="1.5"
/><path
d="M10.335 6.99976C10.335 7.41397 9.99917 7.74976 9.58496 7.74976C9.17075 7.74976 8.83496 7.41397 8.83496 6.99976C8.83496 6.58554 9.17075 6.24976 9.58496 6.24976C9.99917 6.24976 10.335 6.58554 10.335 6.99976Z"
stroke="#1C274C"
stroke-width="1.5"
/><path
d="M15.25 7C15.25 7.41421 14.9142 7.75 14.5 7.75C14.0858 7.75 13.75 7.41421 13.75 7C13.75 6.58579 14.0858 6.25 14.5 6.25C14.9142 6.25 15.25 6.58579 15.25 7Z"
stroke="#1C274C"
stroke-width="1.5"
/>
</g>
</svg>
@@ -1,12 +0,0 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let opacity: string = '1'
const fill: string = 'currentColor'
</script>
<svg xmlns="http://www.w3.org/2000/svg" class="svg-{size}" {fill} viewBox="0 0 16 16">
<path
{opacity}
d="M 8 1.320313 L 0.660156 8.132813 L 1.339844 8.867188 L 2 8.253906 L 2 14 L 7 14 L 7 9 L 9 9 L 9 14 L 14 14 L 14 8.253906 L 14.660156 8.867188 L 15.339844 8.132813 Z M 8 2.679688 L 13 7.328125 L 13 13 L 10 13 L 10 8 L 6 8 L 6 13 L 3 13 L 3 7.328125 Z"
/>
</svg>
@@ -1,12 +0,0 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let opacity: string = '1'
const fill: string = 'currentColor'
</script>
<svg xmlns="http://www.w3.org/2000/svg" class="svg-{size}" {fill} viewBox="0 0 16 16">
<path
{opacity}
d="M 14.5 2.792969 L 5.5 11.792969 L 1.851563 8.148438 L 1.5 7.792969 L 0.792969 8.5 L 1.148438 8.851563 L 5.5 13.207031 L 15.207031 3.5 Z"
/>
</svg>
@@ -1,16 +0,0 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let opacity: string = '1'
</script>
<svg class="svg-{size}" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g {opacity}>
<path
d="M14.1665 7.5L11.789 11.0662C11.3631 11.7051 10.4059 11.6455 10.0625 10.9587L9.93713 10.7079C9.59375 10.0212 8.63657 9.96157 8.21066 10.6004L5.83317 14.1667"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<rect x="2.5" y="2.5" width="15" height="15" rx="2" stroke="currentColor" />
</g>
</svg>
@@ -13,11 +13,12 @@
// limitations under the License.
-->
<script lang="ts">
import { getContext } from 'svelte'
import { getContext, onMount } from 'svelte'
import { getMetadata } from '@hcengineering/platform'
import ui, { showPopup, deviceOptionsStore as deviceInfo } from '../..'
import LangPopup from './LangPopup.svelte'
import Html from '../Html.svelte'
import { updateEmojis } from '../emoji'
let pressed: boolean = false
@@ -62,11 +63,15 @@
if (result) {
selected = langs.find((item) => item.id === result)
setLanguage(result)
void updateEmojis(result)
}
pressed = false
})
}
$: $deviceInfo.language = selected?.id
onMount(() => {
void updateEmojis()
})
</script>
<button
+1 -2
View File
@@ -217,7 +217,6 @@ export { default as IconCircles } from './components/icons/Circles.svelte'
export { default as IconLike } from './components/icons/Like.svelte'
export { default as IconCollapseArrow } from './components/icons/CollapseArrow.svelte'
export { default as IconEmoji } from './components/icons/Emoji.svelte'
export { default as IconObjects } from './components/icons/Objects.svelte'
export { default as IconUndo } from './components/icons/Undo.svelte'
export { default as IconRedo } from './components/icons/Redo.svelte'
export { default as IconOpenedArrow } from './components/icons/OpenedArrow.svelte'
@@ -269,7 +268,6 @@ export { NotificationSeverity } from './components/notifications/NotificationSev
export type { Notification } from './components/notifications/Notification'
export { default as Wizard } from './components/wizard/Wizard.svelte'
export { default as StepsDialog } from './components/StepsDialog.svelte'
export { default as EmojiPopup } from './components/EmojiPopup.svelte'
export { default as IconWithEmoji } from './components/IconWithEmoji.svelte'
export { default as ModeSelector } from './components/ModeSelector.svelte'
export { default as SimpleTimePopup } from './components/calendar/SimpleTimePopup.svelte'
@@ -299,6 +297,7 @@ export * from './colors'
export * from './focus'
export * from './resize'
export * from './lazy'
export * from './components/emoji'
export function createApp (target: HTMLElement): SvelteComponent {
return new Root({ target })
+20 -7
View File
@@ -51,6 +51,7 @@ export const uis = plugin(uiId, {
ShowLess: '' as IntlString,
Search: '' as IntlString,
SearchDots: '' as IntlString,
SearchResults: '' as IntlString,
Suggested: '' as IntlString,
TimeTooltip: '' as IntlString,
SelectDate: '' as IntlString,
@@ -101,15 +102,27 @@ export const uis = plugin(uiId, {
DueDatePopupDescription: '' as IntlString,
DueDatePopupOverdueDescription: '' as IntlString,
GettingWorkDone: '' as IntlString,
ExpressYourself: '' as IntlString,
Smileys: '' as IntlString,
Nature: '' as IntlString,
Symbols: '' as IntlString,
SmileysAndPeople: '' as IntlString,
Components: '' as IntlString,
AnimalsAndNature: '' as IntlString,
FoodAndDrink: '' as IntlString,
TravelAndPlaces: '' as IntlString,
Food: '' as IntlString,
MoreCount: '' as IntlString,
Activities: '' as IntlString,
Objects: '' as IntlString,
Symbols: '' as IntlString,
Flags: '' as IntlString,
FrequentlyUsed: '' as IntlString,
GettingWorkDone: '' as IntlString,
DefaultSkinTone: '' as IntlString,
NoTone: '' as IntlString,
Light: '' as IntlString,
MediumLight: '' as IntlString,
Medium: '' as IntlString,
MediumDark: '' as IntlString,
Dark: '' as IntlString,
Remove: '' as IntlString,
NoResults: '' as IntlString,
MoreCount: '' as IntlString,
Spacious: '' as IntlString,
Compact: '' as IntlString,
ThemeLight: '' as IntlString,
+1 -1
View File
@@ -429,7 +429,7 @@ export function fitPopupElement (
return { props: newProps, showOverlay: show, direction: '' }
}
export function eventToHTMLElement (evt: MouseEvent): HTMLElement {
export function eventToHTMLElement (evt: MouseEvent | TouchEvent): HTMLElement {
return evt.target as HTMLElement
}
@@ -51,7 +51,7 @@
</script>
<PopupDialog label={view.string.ChooseIcon} on:changeContent>
<div class="float-left-box w-85">
<div class="flex-col float-left-box maxWidth">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<TabsControl size={'small'} {model}>
@@ -110,5 +110,13 @@
.pallete {
display: flex;
flex-wrap: wrap;
min-width: 0;
min-height: 0;
}
.maxWidth {
width: 25rem;
height: 30rem;
min-width: 0;
min-height: 0;
}
</style>
@@ -21,7 +21,7 @@
export let embedded: boolean = false
</script>
<div class:card-container={!embedded}>
<div class={embedded ? 'clear-mins' : 'card-container'}>
<div class="overflow-label label"><Label {label} /></div>
<div class="content"><slot /></div>
</div>
@@ -32,6 +32,8 @@
display: flex;
flex-direction: column;
padding: 1rem 1.5rem 1.5rem;
min-width: 0;
min-height: 0;
border-radius: 0.5rem;
background-color: var(--theme-popup-color);
border: 1px solid var(--theme-popup-divider);
@@ -48,7 +50,7 @@
.content {
flex-shrink: 0;
flex-grow: 1;
height: fit-content;
// height: fit-content;
}
}
</style>
+1 -1
View File
@@ -79,7 +79,7 @@ export class ChannelPage extends CommonPage {
private readonly addMemberPreview = (): Locator => this.page.getByRole('button', { name: 'Add members' })
private readonly addButtonPreview = (): Locator => this.page.getByRole('button', { name: 'Add', exact: true })
readonly inputSearchIcon = (): Locator => this.page.locator('.searchInput-icon')
readonly inputSearchIcon = (): Locator => this.page.locator('.searchInput-wrapper')
readonly inputSearchChannel = (): Locator => this.page.locator('.hulyHeader-container').getByPlaceholder('Search')
readonly channelContainers = (): Locator => this.page.locator('.hulyNavItem-container')
+1 -1
View File
@@ -20,7 +20,7 @@ export class CommonPage {
popupSpanLabel = (point: string): Locator =>
this.page.locator(`div[class$="opup"] span[class*="label"]:has-text("${point}")`)
readonly inputSearchIcon = (): Locator => this.page.locator('.searchInput-icon')
readonly inputSearchIcon = (): Locator => this.page.locator('.searchInput-wrapper')
selectPopupSpanLines = (item: string): Locator =>
this.page.locator('div.selectPopup span[class^="lines"]', { hasText: item })
+2 -2
View File
@@ -36,7 +36,7 @@ export class SettingsPage extends CommonPage {
selectIconButton = (): Locator => this.page.locator('button[data-id="btnSelectIcon"]')
emojiSectionButton = (): Locator => this.page.locator('div.popup div.tab', { hasText: 'Emoji' })
emojiIconButton = (hasText: string): Locator => this.page.locator('div.popup div.element', { hasText })
emojiIconButton = (hasText: string): Locator => this.page.getByRole('button', { name: hasText }).first()
taskTypeRow = (value: string): Locator =>
this.page
.locator('div.hulyTableAttr-header', { hasText: 'Task types' })
@@ -133,6 +133,6 @@ export class SettingsPage extends CommonPage {
async changeIcon (): Promise<void> {
await this.selectIconButton().click()
await this.emojiSectionButton().click()
await this.emojiIconButton('').click()
await this.emojiIconButton('👀').click()
}
}
@@ -50,7 +50,7 @@ export class IssuesPage extends CommonTrackerPage {
textPopupCreateNewIssueFile = (): Locator => this.page.locator('div[class*="attachments"] > div[class*="attachment"]')
buttonCreateIssue = (): Locator => this.page.locator('button > span', { hasText: 'Create issue' })
inputSearchIcon = (): Locator => this.page.locator('.searchInput-icon')
inputSearchIcon = (): Locator => this.page.locator('.searchInput-wrapper')
inputSearch = (): Locator => this.page.locator('input[placeholder="Search"]')
linkSidebarAll = (): Locator => this.page.locator('a[href$="all-issues"]')
linkSidebarMyIssue = (): Locator => this.page.locator('a[href$="my-issues"]')
+1 -1
View File
@@ -117,7 +117,7 @@ export function generateId (len = 100): string {
* @returns {Promise<Locator>}
*/
export async function fillSearch (page: Page, search: string): Promise<Locator> {
await page.locator('.searchInput-icon').click()
await page.locator('.searchInput-wrapper').click()
const searchBox = page.locator('input[placeholder="Search"]')
await searchBox.fill(search)