From 2a2793eada7da5a1699c1743762fc314ed149c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ShellWen=20=7C=20=E9=A2=89=E6=96=87=2C=20Chen=20Chang?= Date: Sun, 21 Sep 2025 22:17:32 +0800 Subject: [PATCH 01/28] fix: Correct spacing in AI partner description (#13593) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed spacing issue in AI partner description. ## Summary by CodeRabbit * **Documentation** * Improved readability by fixing a minor punctuation/spacing issue in the project’s introductory text (added a space after a comma). * Polished wording to better reflect professional tone without altering meaning. * No changes to functionality, configuration, or user workflows. * No impact on APIs, interfaces, or compatibility. * No additional steps required for users; purely a documentation refinement. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8e188dfba4..da2fcc4f43 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Star us, and you will receive all release notifications from GitHub without any **Multimodal AI partner ready to kick in any work** -- Write up professional work report? Turn an outline into expressive and presentable slides? Summary an article into a well-structured mindmap? Sorting your job plan and backlog for tasks? Or... draw and code prototype apps and web pages directly all with one prompt? With you, [AFFiNE AI](https://affine.pro/ai) pushes your creativity to the edge of your imagination,just like [Canvas AI](https://affine.pro/blog/best-canvas-ai) to generate mind map for brainstorming. +- Write up professional work report? Turn an outline into expressive and presentable slides? Summary an article into a well-structured mindmap? Sorting your job plan and backlog for tasks? Or... draw and code prototype apps and web pages directly all with one prompt? With you, [AFFiNE AI](https://affine.pro/ai) pushes your creativity to the edge of your imagination, just like [Canvas AI](https://affine.pro/blog/best-canvas-ai) to generate mind map for brainstorming. **Local-first & Real-time collaborative** From 19bd29e90c282b26973e93cc3b8d14e71e0bf4eb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Sep 2025 22:22:59 +0800 Subject: [PATCH 02/28] chore: bump up apple/swift-collections version to from: "1.2.1" (#13535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coming soon: The Renovate bot (GitHub App) will be renamed to Mend. PRs from Renovate will soon appear from 'Mend'. Learn more [here](https://redirect.github.com/renovatebot/renovate/discussions/37842). This PR contains the following updates: | Package | Update | Change | |---|---|---| | [apple/swift-collections](https://redirect.github.com/apple/swift-collections) | patch | `from: "1.2.0"` -> `from: "1.2.1"` | --- ### Release Notes
apple/swift-collections (apple/swift-collections) ### [`v1.2.1`](https://redirect.github.com/apple/swift-collections/releases/tag/1.2.1): Swift Collections 1.2.1 [Compare Source](https://redirect.github.com/apple/swift-collections/compare/1.2.0...1.2.1) This is a patch release with the following minor improvements: - `BigString` sometimes miscounted distances in its character view, resulting in an invalid collection conformance. This is now fixed. ([#​485](https://redirect.github.com/apple/swift-collections/issues/485)) - `BigString`'s Unicode Scalar and character views now make better use of known lengths of the text chunks stored in the tree, resulting in significantly improved performance for their distance measurements. ([#​486](https://redirect.github.com/apple/swift-collections/issues/486)) - The Foundation-specific toolchain configuration was updated to include the Deque type. ([#​496](https://redirect.github.com/apple/swift-collections/issues/496)) #### What's Changed - \[BigString] Fix character indexing operations by [@​lorentey](https://redirect.github.com/lorentey) in [#​485](https://redirect.github.com/apple/swift-collections/pull/485) - \[BigString] Harvest some low-hanging performance fruit by [@​lorentey](https://redirect.github.com/lorentey) in [#​486](https://redirect.github.com/apple/swift-collections/pull/486) - Include DequeModule in the Foundation toolchain build by [@​cthielen](https://redirect.github.com/cthielen) in [#​496](https://redirect.github.com/apple/swift-collections/pull/496) **Full Changelog**:
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../frontend/apps/ios/App/Packages/Intelligents/Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift b/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift index 054c18b070..5a2721d64a 100644 --- a/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift +++ b/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift @@ -16,7 +16,7 @@ let package = Package( .package(path: "../AffineGraphQL"), .package(path: "../AffineResources"), .package(url: "https://github.com/apollographql/apollo-ios.git", from: "1.22.0"), - .package(url: "https://github.com/apple/swift-collections.git", from: "1.2.0"), + .package(url: "https://github.com/apple/swift-collections.git", from: "1.2.1"), .package(url: "https://github.com/SnapKit/SnapKit.git", from: "5.7.1"), .package(url: "https://github.com/SwifterSwift/SwifterSwift.git", from: "6.0.0"), .package(url: "https://github.com/Recouse/EventSource.git", from: "0.1.4"), From 4efbb630fccfc3dafc690636e694a7011a073499 Mon Sep 17 00:00:00 2001 From: Richard Lora Date: Sun, 21 Sep 2025 10:43:46 -0400 Subject: [PATCH 03/28] fix(core): correct emoji extraction logic using regex (#12749) https://github.com/user-attachments/assets/ef612f34-0388-49a2-bcad-0cac07a5f785 This PR solves the issue where a majority of emoji's are unable to become the document or folders icon. The regex used is below with the test string of a variety of emoji's: https://regex101.com/r/0anB6Z/1 Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com> --- .../utils/__tests__/extract-emoji-icon.spec.ts | 17 ++++++++++++++++- .../core/src/utils/extract-emoji-icon.ts | 11 +++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/frontend/core/src/utils/__tests__/extract-emoji-icon.spec.ts b/packages/frontend/core/src/utils/__tests__/extract-emoji-icon.spec.ts index 3828b7e09a..a4031767fc 100644 --- a/packages/frontend/core/src/utils/__tests__/extract-emoji-icon.spec.ts +++ b/packages/frontend/core/src/utils/__tests__/extract-emoji-icon.spec.ts @@ -9,7 +9,22 @@ test('extract-emoji-icon', () => { }); expect(extractEmojiIcon('❤️123')).toEqual({ + emoji: '❤️', + rest: '123', + }); + + expect(extractEmojiIcon('➡️456')).toEqual({ + emoji: '➡️', + rest: '456', + }); + + expect(extractEmojiIcon('✈️789')).toEqual({ + emoji: '✈️', + rest: '789', + }); + + expect(extractEmojiIcon('plain text')).toEqual({ emoji: null, - rest: '❤️123', + rest: 'plain text', }); }); diff --git a/packages/frontend/core/src/utils/extract-emoji-icon.ts b/packages/frontend/core/src/utils/extract-emoji-icon.ts index 8fb7b1a1b3..83ca7dbfae 100644 --- a/packages/frontend/core/src/utils/extract-emoji-icon.ts +++ b/packages/frontend/core/src/utils/extract-emoji-icon.ts @@ -1,13 +1,16 @@ import Graphemer from 'graphemer'; +const emojiRe = + /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g; export function extractEmojiIcon(text: string) { - const isStartsWithEmoji = /^(\p{Emoji_Presentation})/u.test(text); - if (isStartsWithEmoji) { + emojiRe.lastIndex = 0; + const match = emojiRe.exec(text); + if (match && match.index === 0) { // emoji like "👨🏻‍❤️‍💋‍👨🏻" are combined. Graphemer can handle these. const emojiEnd = Graphemer.nextBreak(text, 0); return { - emoji: text.substring(0, emojiEnd), - rest: text.substring(emojiEnd), + emoji: text.slice(0, emojiEnd), + rest: text.slice(emojiEnd), }; } return { From d231b47f1f906178ae48e08349a5d363c4d70776 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Sep 2025 14:35:11 +0000 Subject: [PATCH 04/28] chore: bump up nestjs (#13614) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coming soon: The Renovate bot (GitHub App) will be renamed to Mend. PRs from Renovate will soon appear from 'Mend'. Learn more [here](https://redirect.github.com/renovatebot/renovate/discussions/37842). This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [@nestjs/bullmq](https://redirect.github.com/nestjs/bull) | [`11.0.2` -> `11.0.3`](https://renovatebot.com/diffs/npm/@nestjs%2fbullmq/11.0.2/11.0.3) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fbullmq/11.0.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fbullmq/11.0.2/11.0.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [@nestjs/common](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/common)) | [`11.1.5` -> `11.1.6`](https://renovatebot.com/diffs/npm/@nestjs%2fcommon/11.1.5/11.1.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fcommon/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fcommon/11.1.5/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [@nestjs/core](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/core)) | [`11.1.5` -> `11.1.6`](https://renovatebot.com/diffs/npm/@nestjs%2fcore/11.1.5/11.1.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fcore/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fcore/11.1.5/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [@nestjs/platform-express](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/platform-express)) | [`11.1.5` -> `11.1.6`](https://renovatebot.com/diffs/npm/@nestjs%2fplatform-express/11.1.5/11.1.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fplatform-express/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fplatform-express/11.1.5/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [@nestjs/platform-socket.io](https://nestjs.com) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/platform-socket.io)) | [`11.1.5` -> `11.1.6`](https://renovatebot.com/diffs/npm/@nestjs%2fplatform-socket.io/11.1.5/11.1.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fplatform-socket.io/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fplatform-socket.io/11.1.5/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [@nestjs/schedule](https://redirect.github.com/nestjs/schedule) | [`6.0.0` -> `6.0.1`](https://renovatebot.com/diffs/npm/@nestjs%2fschedule/6.0.0/6.0.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fschedule/6.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fschedule/6.0.0/6.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [@nestjs/websockets](https://redirect.github.com/nestjs/nest) ([source](https://redirect.github.com/nestjs/nest/tree/HEAD/packages/websockets)) | [`11.1.5` -> `11.1.6`](https://renovatebot.com/diffs/npm/@nestjs%2fwebsockets/11.1.5/11.1.6) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs%2fwebsockets/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs%2fwebsockets/11.1.5/11.1.6?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
nestjs/bull (@​nestjs/bullmq) ### [`v11.0.3`](https://redirect.github.com/nestjs/bull/releases/tag/%40nestjs/bullmq%4011.0.3) [Compare Source](https://redirect.github.com/nestjs/bull/compare/@nestjs/bullmq@11.0.2...@nestjs/bullmq@11.0.3) #### What's Changed - feat(bullmq): add telemetry support for workers by [@​noeljackson](https://redirect.github.com/noeljackson) in [#​2585](https://redirect.github.com/nestjs/bull/pull/2585) #### New Contributors - [@​noeljackson](https://redirect.github.com/noeljackson) made their first contribution in [#​2585](https://redirect.github.com/nestjs/bull/pull/2585) **Full Changelog**:
nestjs/nest (@​nestjs/common) ### [`v11.1.6`](https://redirect.github.com/nestjs/nest/releases/tag/v11.1.6) [Compare Source](https://redirect.github.com/nestjs/nest/compare/v11.1.5...v11.1.6) ##### v11.1.6 (2025-08-07) ##### Bug fixes - `core` - [#​15504](https://redirect.github.com/nestjs/nest/pull/15504) fix(core): fix race condition in class dependency resolution from imported modules ([@​hajekjiri](https://redirect.github.com/hajekjiri)) - [#​15469](https://redirect.github.com/nestjs/nest/pull/15469) fix(core): attach root inquirer for nested transient providers ([@​kamilmysliwiec](https://redirect.github.com/kamilmysliwiec)) - `microservices` - [#​15508](https://redirect.github.com/nestjs/nest/pull/15508) fix(microservices): report correct buffer length in exception ([@​kim-sung-jee](https://redirect.github.com/kim-sung-jee)) - [#​15492](https://redirect.github.com/nestjs/nest/pull/15492) fix(microservices): fix kafka serilization of class instances ([@​LeonBiersch](https://redirect.github.com/LeonBiersch)) ##### Dependencies - `platform-fastify` - [#​15493](https://redirect.github.com/nestjs/nest/pull/15493) chore(deps): bump [@​fastify/cors](https://redirect.github.com/fastify/cors) from 11.0.1 to 11.1.0 ([@​dependabot\[bot\]](https://redirect.github.com/apps/dependabot)) ##### Committers: 6 - Jiri Hajek ([@​hajekjiri](https://redirect.github.com/hajekjiri)) - Kamil Mysliwiec ([@​kamilmysliwiec](https://redirect.github.com/kamilmysliwiec)) - Leon Biersch ([@​LeonBiersch](https://redirect.github.com/LeonBiersch)) - Seongjee Kim ([@​kim-sung-jee](https://redirect.github.com/kim-sung-jee)) - [@​premierbell](https://redirect.github.com/premierbell) - pTr ([@​ptrgits](https://redirect.github.com/ptrgits))
nestjs/schedule (@​nestjs/schedule) ### [`v6.0.1`](https://redirect.github.com/nestjs/schedule/releases/tag/6.0.1) [Compare Source](https://redirect.github.com/nestjs/schedule/compare/6.0.0...6.0.1) #### What's Changed - Add threshold to CronOptions by [@​arjunatlightspeed](https://redirect.github.com/arjunatlightspeed) in [#​2085](https://redirect.github.com/nestjs/schedule/pull/2085) - refactor : clear jobs before application shutdown by [@​spotlight21c](https://redirect.github.com/spotlight21c) in [#​2053](https://redirect.github.com/nestjs/schedule/pull/2053) - fix(deps): update dependency cron to v4.3.3 by [@​renovate](https://redirect.github.com/renovate)\[bot] in [#​2001](https://redirect.github.com/nestjs/schedule/pull/2001) #### New Contributors - [@​arjunatlightspeed](https://redirect.github.com/arjunatlightspeed) made their first contribution in [#​2085](https://redirect.github.com/nestjs/schedule/pull/2085) - [@​spotlight21c](https://redirect.github.com/spotlight21c) made their first contribution in [#​2053](https://redirect.github.com/nestjs/schedule/pull/2053) **Full Changelog**:
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/yarn.lock b/yarn.lock index b85ea49dfc..d62c53cb5e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9110,35 +9110,35 @@ __metadata: languageName: node linkType: hard -"@nestjs/bull-shared@npm:^11.0.2": - version: 11.0.2 - resolution: "@nestjs/bull-shared@npm:11.0.2" +"@nestjs/bull-shared@npm:^11.0.3": + version: 11.0.3 + resolution: "@nestjs/bull-shared@npm:11.0.3" dependencies: tslib: "npm:2.8.1" peerDependencies: "@nestjs/common": ^10.0.0 || ^11.0.0 "@nestjs/core": ^10.0.0 || ^11.0.0 - checksum: 10/5ddd639104241c3d7cfef0366fda3b9900dcb250b1a251566bc866a1dab1ada84ce5118efc1455d27a261e86f4b802893237a00e5876748ffb0759086aa02a13 + checksum: 10/3e24f66f4673bf9213fc20c495ef6c62860a839ce4f385453c190fe57840b82adb76b3244d97168d1ea0b557cbb861e739980117422daddd0692ba1013882ae2 languageName: node linkType: hard "@nestjs/bullmq@npm:^11.0.2": - version: 11.0.2 - resolution: "@nestjs/bullmq@npm:11.0.2" + version: 11.0.3 + resolution: "@nestjs/bullmq@npm:11.0.3" dependencies: - "@nestjs/bull-shared": "npm:^11.0.2" + "@nestjs/bull-shared": "npm:^11.0.3" tslib: "npm:2.8.1" peerDependencies: "@nestjs/common": ^10.0.0 || ^11.0.0 "@nestjs/core": ^10.0.0 || ^11.0.0 bullmq: ^3.0.0 || ^4.0.0 || ^5.0.0 - checksum: 10/eac510862401d06898e3222e5979c0b16c0026e0048858d64365a714538bd4838d3d030c0cc18b396a6eab978aab0cc33b82dd3fb340757fcb813073b0cae370 + checksum: 10/3f5fc685b5ea7d1d9590ea6b3594df3e684a208a115e637b1366963af0167276d4eee35b2085324ed6be4d751d249466ccf707a28120c090063f0d6afc8c2015 languageName: node linkType: hard "@nestjs/common@npm:^11.0.12": - version: 11.1.5 - resolution: "@nestjs/common@npm:11.1.5" + version: 11.1.6 + resolution: "@nestjs/common@npm:11.1.6" dependencies: file-type: "npm:21.0.0" iterare: "npm:1.2.1" @@ -9155,13 +9155,13 @@ __metadata: optional: true class-validator: optional: true - checksum: 10/419ccee948e6113751d6d2e949daff2fd00d255150414f29c5164e7393f0944a53e2366a387c9751afec73cab5fe019a9b1e2ef940cdd44876222b8b262643fe + checksum: 10/bb8a8f040ecaad5ea4938d166afa5e077060372001def3694999bdd8695dd6d69845c4569ade94aecb4f6b625198d3e848270ecc29be7ba5d73aefe5edd76984 languageName: node linkType: hard "@nestjs/core@npm:^11.0.12": - version: 11.1.5 - resolution: "@nestjs/core@npm:11.1.5" + version: 11.1.6 + resolution: "@nestjs/core@npm:11.1.6" dependencies: "@nuxt/opencollective": "npm:0.4.1" fast-safe-stringify: "npm:2.1.1" @@ -9183,7 +9183,7 @@ __metadata: optional: true "@nestjs/websockets": optional: true - checksum: 10/0086f5a8080bec35a53b4332dd1a786ed02e2e36d0fb5cd75ca1b19340b0a40d1a381a49817c494e445dc92243d9ba1d97746a5262ba721df327114d66d86422 + checksum: 10/d38c32eea96f9a475907e352b1f9f0441bf1bd4de2fa479836930e9670072deb1c1986253da324eb85bbcb884515d90ad2f10e88e49e491ac888b6893cc1faf3 languageName: node linkType: hard @@ -9244,8 +9244,8 @@ __metadata: linkType: hard "@nestjs/platform-express@npm:^11.0.12": - version: 11.1.5 - resolution: "@nestjs/platform-express@npm:11.1.5" + version: 11.1.6 + resolution: "@nestjs/platform-express@npm:11.1.6" dependencies: cors: "npm:2.8.5" express: "npm:5.1.0" @@ -9255,13 +9255,13 @@ __metadata: peerDependencies: "@nestjs/common": ^11.0.0 "@nestjs/core": ^11.0.0 - checksum: 10/b82cf1b80078fb15757448c279ff51e24cf210d7ceeaae2c2569553b772931ef396cd48d0b77045e63b78df632589d3b8ec433cddafc64f51df59f8fd41b8507 + checksum: 10/06e14cbfd587ba2ce51c2336d2ad4c5990e95f95ddf829b75125b998449a4186532ad0e65d148a566a49e3503d9e7dab476c3a4720d053ef430a243e70650d69 languageName: node linkType: hard "@nestjs/platform-socket.io@npm:^11.0.12": - version: 11.1.5 - resolution: "@nestjs/platform-socket.io@npm:11.1.5" + version: 11.1.6 + resolution: "@nestjs/platform-socket.io@npm:11.1.6" dependencies: socket.io: "npm:4.8.1" tslib: "npm:2.8.1" @@ -9269,19 +9269,19 @@ __metadata: "@nestjs/common": ^11.0.0 "@nestjs/websockets": ^11.0.0 rxjs: ^7.1.0 - checksum: 10/c6c3d96d98d095fde1766e8c294f4e1760816f337828e09293bede7747117ccf728b1f96f4ac3a2c1f7be0582824858b5ec0c89343fe96cb047d83e4dd2c3222 + checksum: 10/8d36586b2cdc66f19e35b55fbb47019871f6acf8d7d30330fe1965a35cbeb7f9b60424b35a6c61733410896d58b831c56eb31b62d16d4b8eb96b020fd416c3ff languageName: node linkType: hard "@nestjs/schedule@npm:^6.0.0": - version: 6.0.0 - resolution: "@nestjs/schedule@npm:6.0.0" + version: 6.0.1 + resolution: "@nestjs/schedule@npm:6.0.1" dependencies: - cron: "npm:4.3.0" + cron: "npm:4.3.3" peerDependencies: "@nestjs/common": ^10.0.0 || ^11.0.0 "@nestjs/core": ^10.0.0 || ^11.0.0 - checksum: 10/84f4c11f9fe3aa6d5e7b3c4d0e27f610e47394e87b2974bf0b7a169832b52343daf9ca1c5717caf642d9b134d8a0ae2ce5ab3dca5562d41781b92ddc96a91043 + checksum: 10/7c9e892c1e495ddd49531e783171a9a38b991d69d2060caa25709f886f458b034811bddebbb80fa7cdffd0f4578b0f81d4f0fbfe27e0ae11b6a358775fac8e6f languageName: node linkType: hard @@ -9335,8 +9335,8 @@ __metadata: linkType: hard "@nestjs/websockets@npm:^11.0.12": - version: 11.1.5 - resolution: "@nestjs/websockets@npm:11.1.5" + version: 11.1.6 + resolution: "@nestjs/websockets@npm:11.1.6" dependencies: iterare: "npm:1.2.1" object-hash: "npm:3.0.0" @@ -9350,7 +9350,7 @@ __metadata: peerDependenciesMeta: "@nestjs/platform-socket.io": optional: true - checksum: 10/2a916dcd8bb75fff561b4d5c9a18304d33e0525de6162c24deef4908cd4a062261d4d8ac729b35eef0aedcc5837c9b344591ba9310784920f014811790a1999c + checksum: 10/b4ebae17afbfc5c70ee5d66dd0b7b23d3d6d12fb98678f5a00069e0f009916c0119583810b92bba878a99d5488fc3f6134ce84bf5f8cdfd73ff0d54ec0e4f33a languageName: node linkType: hard @@ -15152,10 +15152,10 @@ __metadata: languageName: node linkType: hard -"@types/luxon@npm:~3.6.0": - version: 3.6.2 - resolution: "@types/luxon@npm:3.6.2" - checksum: 10/73ca30059e0b1e352ce3a208837bc042e0bae9cf6e5b42f63de9ddfe15348a9e9bf9fcde3d4034038be24cb24adc579ae984cadff3bf70432e54fed1ad249d12 +"@types/luxon@npm:~3.7.0": + version: 3.7.1 + resolution: "@types/luxon@npm:3.7.1" + checksum: 10/c7bc164c278393ea0be938f986c74b4cddfab9013b1aff4495b016f771ded1d5b7b7b4825b2c7f0b8799edce19c5f531c28ff434ab3dedf994ac2d99a20fd4c4 languageName: node linkType: hard @@ -19302,13 +19302,13 @@ __metadata: languageName: node linkType: hard -"cron@npm:4.3.0": - version: 4.3.0 - resolution: "cron@npm:4.3.0" +"cron@npm:4.3.3": + version: 4.3.3 + resolution: "cron@npm:4.3.3" dependencies: - "@types/luxon": "npm:~3.6.0" - luxon: "npm:~3.6.0" - checksum: 10/202d9eef7da7c3cae548ef0e0fd20a0ee2f41ca36cca1486ba4ecd16783d02ebc6c116c84572aef0ce6c85c9f290eba9ff00e1a8eda2053123cf2c9d68a4702a + "@types/luxon": "npm:~3.7.0" + luxon: "npm:~3.7.0" + checksum: 10/14019a639e08a8cd3eeb25dcc0541ee5cdae706ef925ac97a964ab7045284b3d3e7058f122dde6e9ff6931c836ea49c41675235d96e361365f6dd1e67bf0d347 languageName: node linkType: hard @@ -26094,10 +26094,10 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.2.1, luxon@npm:~3.6.0": - version: 3.6.1 - resolution: "luxon@npm:3.6.1" - checksum: 10/35aad425607708c87af110a52c949190bc35b987770079ec8007ef2365cd29639413db3360d2883777aa01cb3ca5bdb37f42ee3e8e5a0dd277fe22e90cc8a786 +"luxon@npm:^3.2.1, luxon@npm:~3.7.0": + version: 3.7.2 + resolution: "luxon@npm:3.7.2" + checksum: 10/b24cd205ed306ce7415991687897dcc4027921ae413c9116590bc33a95f93b86ce52cf74ba72b4f5c5ab1c10090517f54ac8edfb127c049e0bf55b90dc2260be languageName: node linkType: hard From 750b008dc8ee7bda1b83293f275ac364bdc82e5e Mon Sep 17 00:00:00 2001 From: Bl4ckspell Date: Sun, 21 Sep 2025 16:51:10 +0200 Subject: [PATCH 05/28] feat(android): add monochrome icon support (#13527) Add missing themed icon support for android app icon. ## Summary by CodeRabbit * **New Features** * Android app icon now supports a monochrome variant for adaptive icons, enabling themed icons on compatible launchers. * Improved icon consistency and visibility across system themes (including dark mode). * Applied to both standard and round launcher icons. --- .../App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | 1 + .../App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/frontend/apps/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/packages/frontend/apps/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index bbd3e02123..50ec886232 100644 --- a/packages/frontend/apps/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/packages/frontend/apps/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/packages/frontend/apps/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index bbd3e02123..50ec886232 100644 --- a/packages/frontend/apps/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/packages/frontend/apps/android/App/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -2,4 +2,5 @@ + \ No newline at end of file From 21bb8142b0eee7a31e015a60f27d8dd7795d419f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Sep 2025 14:54:00 +0000 Subject: [PATCH 06/28] chore: bump up Recouse/EventSource version to from: "0.1.5" (#13620) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coming soon: The Renovate bot (GitHub App) will be renamed to Mend. PRs from Renovate will soon appear from 'Mend'. Learn more [here](https://redirect.github.com/renovatebot/renovate/discussions/37842). This PR contains the following updates: | Package | Update | Change | |---|---|---| | [Recouse/EventSource](https://redirect.github.com/Recouse/EventSource) | patch | `from: "0.1.4"` -> `from: "0.1.5"` | --- ### Release Notes
Recouse/EventSource (Recouse/EventSource) ### [`v0.1.5`](https://redirect.github.com/Recouse/EventSource/releases/tag/0.1.5) [Compare Source](https://redirect.github.com/Recouse/EventSource/compare/0.1.4...0.1.5) #### What's Changed - Fix potential data corruption by [@​Recouse](https://redirect.github.com/Recouse) in [#​30](https://redirect.github.com/Recouse/EventSource/pull/30) - Concurrency improvements by [@​Recouse](https://redirect.github.com/Recouse) in [#​31](https://redirect.github.com/Recouse/EventSource/pull/31) - Update EventParser.swift to Support CR LF by [@​Lakr233](https://redirect.github.com/Lakr233) in [#​28](https://redirect.github.com/Recouse/EventSource/pull/28) #### New Contributors - [@​Lakr233](https://redirect.github.com/Lakr233) made their first contribution in [#​28](https://redirect.github.com/Recouse/EventSource/pull/28) **Full Changelog**:
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../frontend/apps/ios/App/Packages/Intelligents/Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift b/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift index 5a2721d64a..86e9339cc3 100644 --- a/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift +++ b/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift @@ -19,7 +19,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-collections.git", from: "1.2.1"), .package(url: "https://github.com/SnapKit/SnapKit.git", from: "5.7.1"), .package(url: "https://github.com/SwifterSwift/SwifterSwift.git", from: "6.0.0"), - .package(url: "https://github.com/Recouse/EventSource.git", from: "0.1.4"), + .package(url: "https://github.com/Recouse/EventSource.git", from: "0.1.5"), .package(url: "https://github.com/Lakr233/ListViewKit.git", from: "1.1.6"), .package(url: "https://github.com/Lakr233/MarkdownView.git", from: "3.4.2"), ], From 363f64ebfaa6b61f90f2bb34ee3d3075d94124e8 Mon Sep 17 00:00:00 2001 From: Finn Weigand <52424812+Hudint@users.noreply.github.com> Date: Sun, 21 Sep 2025 17:38:25 +0200 Subject: [PATCH 07/28] feat: add dedicated sign-up config for oauth (#13610) Currently, it is only possible to disable all registrations. However, it would be helpful if you could disable normal registration but enable OAuth registration. ## Summary by CodeRabbit * **New Features** * Added a setting to enable/disable new user signups via OAuth (default: enabled). * Admin Settings (Authentication) now includes a toggle for OAuth signups. * OAuth signup flow now respects this setting, preventing new registrations via OAuth when disabled. * Self-hosted configuration schema updated to include the new option. --------- Signed-off-by: Hudint Finn Weigand Co-authored-by: DarkSky Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com> --- .docker/selfhost/schema.json | 5 +++++ packages/backend/server/src/core/auth/config.ts | 5 +++++ packages/backend/server/src/plugins/oauth/controller.ts | 2 +- packages/frontend/admin/src/config.json | 4 ++++ packages/frontend/admin/src/modules/settings/config.ts | 1 + 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.docker/selfhost/schema.json b/.docker/selfhost/schema.json index d8356b1dc1..3b46680d17 100644 --- a/.docker/selfhost/schema.json +++ b/.docker/selfhost/schema.json @@ -148,6 +148,11 @@ "description": "Whether allow new registrations.\n@default true", "default": true }, + "allowSignupForOauth": { + "type": "boolean", + "description": "Whether allow new registrations via configured oauth.\n@default true", + "default": true + }, "requireEmailDomainVerification": { "type": "boolean", "description": "Whether require email domain record verification before accessing restricted resources.\n@default false", diff --git a/packages/backend/server/src/core/auth/config.ts b/packages/backend/server/src/core/auth/config.ts index 05e5695c6f..afd5900541 100644 --- a/packages/backend/server/src/core/auth/config.ts +++ b/packages/backend/server/src/core/auth/config.ts @@ -8,6 +8,7 @@ export interface AuthConfig { ttr: number; }; allowSignup: boolean; + allowSignupForOauth: boolean; requireEmailDomainVerification: boolean; requireEmailVerification: boolean; passwordRequirements: ConfigItem<{ @@ -27,6 +28,10 @@ defineModuleConfig('auth', { desc: 'Whether allow new registrations.', default: true, }, + allowSignupForOauth: { + desc: 'Whether allow new registrations via configured oauth.', + default: true, + }, requireEmailDomainVerification: { desc: 'Whether require email domain record verification before accessing restricted resources.', default: false, diff --git a/packages/backend/server/src/plugins/oauth/controller.ts b/packages/backend/server/src/plugins/oauth/controller.ts index 7738688587..eb7e909e43 100644 --- a/packages/backend/server/src/plugins/oauth/controller.ts +++ b/packages/backend/server/src/plugins/oauth/controller.ts @@ -224,7 +224,7 @@ export class OAuthController { return connectedAccount.user; } - if (!this.config.auth.allowSignup) { + if (!this.config.auth.allowSignupForOauth) { throw new SignUpForbidden(); } diff --git a/packages/frontend/admin/src/config.json b/packages/frontend/admin/src/config.json index b267abd9a0..386ec175eb 100644 --- a/packages/frontend/admin/src/config.json +++ b/packages/frontend/admin/src/config.json @@ -63,6 +63,10 @@ "type": "Boolean", "desc": "Whether allow new registrations." }, + "allowSignupForOauth": { + "type": "Boolean", + "desc": "Whether allow new registrations via configured oauth." + }, "requireEmailDomainVerification": { "type": "Boolean", "desc": "Whether require email domain record verification before accessing restricted resources." diff --git a/packages/frontend/admin/src/modules/settings/config.ts b/packages/frontend/admin/src/modules/settings/config.ts index 4c36fd93ed..815ba3248d 100644 --- a/packages/frontend/admin/src/modules/settings/config.ts +++ b/packages/frontend/admin/src/modules/settings/config.ts @@ -55,6 +55,7 @@ export const KNOWN_CONFIG_GROUPS = [ module: 'auth', fields: [ 'allowSignup', + 'allowSignupForOauth', // nested json object { key: 'passwordRequirements', From e08fc5ef06bbb36f4905f58f9ad45c05266c6103 Mon Sep 17 00:00:00 2001 From: Jachin Date: Mon, 22 Sep 2025 00:08:30 +0800 Subject: [PATCH 08/28] feat(server): change the playground option to GraphiQL. (#13451) ## Summary by CodeRabbit * **New Features** * The GraphQL interactive UI is now available only in development environments and will not be accessible in production. This change affects only the availability of the interactive interface; public exports and API context types remain unchanged. Users in development can continue to use the tool as before, while production deployments will no longer expose the interactive UI. Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com> --- packages/backend/server/src/base/graphql/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend/server/src/base/graphql/index.ts b/packages/backend/server/src/base/graphql/index.ts index 8f8811bc99..57da5da3f6 100644 --- a/packages/backend/server/src/base/graphql/index.ts +++ b/packages/backend/server/src/base/graphql/index.ts @@ -8,6 +8,7 @@ import { Global, Module } from '@nestjs/common'; import { GraphQLModule } from '@nestjs/graphql'; import type { Request, Response } from 'express'; +import { NodeEnv } from '../../env'; import { Config } from '../config'; import { mapAnyError } from '../nestjs/exception'; import { GQLLoggerPlugin } from './logger-plugin'; @@ -30,7 +31,7 @@ export type GraphqlContext = { numberScalarMode: 'integer', }, useGlobalPrefix: true, - playground: true, + graphiql: env.NODE_ENV === NodeEnv.Development, sortSchema: true, autoSchemaFile: join( env.projectRoot, From 2d0721a78ff8ca8daca0ce5a66fc70fdd70bec77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 02:34:43 +0800 Subject: [PATCH 09/28] chore: bump axios from 1.9.0 to 1.12.2 (#13621) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [axios](https://github.com/axios/axios) from 1.9.0 to 1.12.2.
Release notes

Sourced from axios's releases.

Release v1.12.2

Release notes:

Bug Fixes

  • fetch: use current global fetch instead of cached one when env fetch is not specified to keep MSW support; (#7030) (cf78825)

Contributors to this release

Release v1.12.1

Release notes:

Bug Fixes

Contributors to this release

Release v1.12.0

Release notes:

Bug Fixes

Features

  • adapter: surface low‑level network error details; attach original error via cause (#6982) (78b290c)
  • fetch: add fetch, Request, Response env config variables for the adapter; (#7003) (c959ff2)
  • support reviver on JSON.parse (#5926) (2a97634), closes #5924
  • types: extend AxiosResponse interface to include custom headers type (#6782) (7960d34)

Contributors to this release

... (truncated)

Changelog

Sourced from axios's changelog.

1.12.2 (2025-09-14)

Bug Fixes

  • fetch: use current global fetch instead of cached one when env fetch is not specified to keep MSW support; (#7030) (cf78825)

Contributors to this release

1.12.1 (2025-09-12)

Bug Fixes

Contributors to this release

1.12.0 (2025-09-11)

Bug Fixes

Features

  • adapter: surface low‑level network error details; attach original error via cause (#6982) (78b290c)
  • fetch: add fetch, Request, Response env config variables for the adapter; (#7003) (c959ff2)
  • support reviver on JSON.parse (#5926) (2a97634), closes #5924
  • types: extend AxiosResponse interface to include custom headers type (#6782) (7960d34)

Contributors to this release

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=axios&package-manager=npm_and_yarn&previous-version=1.9.0&new-version=1.12.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/toeverything/AFFiNE/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index d62c53cb5e..ae8b7ef24e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17299,13 +17299,13 @@ __metadata: linkType: hard "axios@npm:^1.8.3": - version: 1.9.0 - resolution: "axios@npm:1.9.0" + version: 1.12.2 + resolution: "axios@npm:1.12.2" dependencies: follow-redirects: "npm:^1.15.6" - form-data: "npm:^4.0.0" + form-data: "npm:^4.0.4" proxy-from-env: "npm:^1.1.0" - checksum: 10/a2f90bba56820883879f32a237e2b9ff25c250365dcafd41cec41b3406a3df334a148f90010182dfdadb4b41dc59f6f0b3e8898ff41b666d1157b5f3f4523497 + checksum: 10/886a79770594eaad76493fecf90344b567bd956240609b5dcd09bd0afe8d3e6f1ad6d3257a93a483b6192b409d4b673d9515a34619e3e3ed1b2c0ec2a83b20ba languageName: node linkType: hard @@ -22311,7 +22311,7 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.0": +"form-data@npm:^4.0.0, form-data@npm:^4.0.4": version: 4.0.4 resolution: "form-data@npm:4.0.4" dependencies: From ebf75e4d3198e3b2ebb4134275a80b06981f34b4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Sep 2025 18:35:24 +0000 Subject: [PATCH 10/28] chore: bump up apollographql/apollo-ios version to v1.23.0 (#13623) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coming soon: The Renovate bot (GitHub App) will be renamed to Mend. PRs from Renovate will soon appear from 'Mend'. Learn more [here](https://redirect.github.com/renovatebot/renovate/discussions/37842). This PR contains the following updates: | Package | Update | Change | |---|---|---| | [apollographql/apollo-ios](https://redirect.github.com/apollographql/apollo-ios) | minor | `from: "1.22.0"` -> `from: "1.23.0"` | | [apollographql/apollo-ios](https://redirect.github.com/apollographql/apollo-ios) | minor | `1.22.0` -> `1.23.0` | --- ### Release Notes
apollographql/apollo-ios (apollographql/apollo-ios) ### [`v1.23.0`](https://redirect.github.com/apollographql/apollo-ios/blob/HEAD/CHANGELOG.md#v1230) [Compare Source](https://redirect.github.com/apollographql/apollo-ios/compare/1.22.0...1.23.0) ##### New - **Added `requireNonOptionalMockFields` flag to `ApolloCodegenConfiguration.OutputOptions`. ([#​669](https://redirect.github.com/apollographql/apollo-ios-dev/pull/669)):** Added new flag to codegen output options to allow having non-optional fields in the test mocks if desired. *Thank you to [@​dwroth](https://redirect.github.com/dwroth) for the contribution.* ##### Improvement - **Added public initializer to `DatabaseRow`. ([#​664](https://redirect.github.com/apollographql/apollo-ios-dev/pull/664)):** Not having a public initializer on `DatabasRow` was hindering the ability to create custom `SQLiteDatabase` implementations. This solves that by adding a public initializer to `DatabaseRow`.*Thank you to [@​ChrisLaganiere](https://redirect.github.com/ChrisLaganiere) for the contribution.* ##### Fixed - **Unncessary deprecation warning in codegen options initializer. ([#​3563](https://redirect.github.com/apollographql/apollo-ios/issues/3563)):** Added `@_disfavoredOverload` to the deprecated initialized in `ApolloCodegenConfiguration` to prevent possible warnings caused by the compiler selecting a deprecated initializer versus the new/current initializer. See PR [#​682](https://redirect.github.com/apollographql/apollo-ios-dev/pull/682). *Thank you to [@​CraigSiemens](https://redirect.github.com/CraigSiemens) for raising the issue.*
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../frontend/apps/ios/App/Packages/AffineGraphQL/Package.swift | 2 +- .../frontend/apps/ios/App/Packages/Intelligents/Package.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Package.swift b/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Package.swift index 14a8270da4..62bb88eb1b 100644 --- a/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Package.swift +++ b/packages/frontend/apps/ios/App/Packages/AffineGraphQL/Package.swift @@ -14,7 +14,7 @@ let package = Package( .library(name: "AffineGraphQL", targets: ["AffineGraphQL"]), ], dependencies: [ - .package(url: "https://github.com/apollographql/apollo-ios", exact: "1.22.0"), + .package(url: "https://github.com/apollographql/apollo-ios", exact: "1.23.0"), ], targets: [ .target( diff --git a/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift b/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift index 86e9339cc3..6104663910 100644 --- a/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift +++ b/packages/frontend/apps/ios/App/Packages/Intelligents/Package.swift @@ -15,7 +15,7 @@ let package = Package( dependencies: [ .package(path: "../AffineGraphQL"), .package(path: "../AffineResources"), - .package(url: "https://github.com/apollographql/apollo-ios.git", from: "1.22.0"), + .package(url: "https://github.com/apollographql/apollo-ios.git", from: "1.23.0"), .package(url: "https://github.com/apple/swift-collections.git", from: "1.2.1"), .package(url: "https://github.com/SnapKit/SnapKit.git", from: "5.7.1"), .package(url: "https://github.com/SwifterSwift/SwifterSwift.git", from: "6.0.0"), From 2f38953cf911f03a466355dea2d22077a277f9df Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Sep 2025 18:47:57 +0000 Subject: [PATCH 11/28] chore: bump up electron version to v35.7.5 [SECURITY] (#13561) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coming soon: The Renovate bot (GitHub App) will be renamed to Mend. PRs from Renovate will soon appear from 'Mend'. Learn more [here](https://redirect.github.com/renovatebot/renovate/discussions/37842). This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [electron](https://redirect.github.com/electron/electron) | [`35.5.1` -> `35.7.5`](https://renovatebot.com/diffs/npm/electron/35.5.1/35.7.5) | [![age](https://developer.mend.io/api/mc/badges/age/npm/electron/35.7.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/electron/35.5.1/35.7.5?slim=true)](https://docs.renovatebot.com/merge-confidence/) | ### GitHub Vulnerability Alerts #### [CVE-2025-55305](https://redirect.github.com/electron/electron/security/advisories/GHSA-vmqv-hx8q-j7mg) ### Impact This only impacts apps that have the `embeddedAsarIntegrityValidation` and `onlyLoadAppFromAsar` [fuses](https://www.electronjs.org/docs/latest/tutorial/fuses) enabled. Apps without these fuses enabled are not impacted. Specifically this issue can only be exploited if your app is launched from a filesystem the attacker has write access too. i.e. the ability to edit files inside the `resources` folder in your app installation on Windows which these fuses are supposed to protect against. ### Workarounds There are no app side workarounds, you must update to a patched version of Electron. ### Fixed Versions * `38.0.0-beta.6` * `37.3.1` * `36.8.1` * `35.7.5` ### For more information If you have any questions or comments about this advisory, email us at [security@electronjs.org](mailto:security@electronjs.org) --- ### Release Notes
electron/electron (electron) ### [`v35.7.5`](https://redirect.github.com/electron/electron/releases/tag/v35.7.5): electron v35.7.5 [Compare Source](https://redirect.github.com/electron/electron/compare/v35.7.4...v35.7.5) ##### Release Notes for v35.7.5 > \[!WARNING] > Electron 35.x.y has reached end-of-support as per the project's [support policy](https://www.electronjs.org/docs/latest/tutorial/electron-timelines#version-support-policy). Developers and applications are encouraged to upgrade to a newer version of Electron. ##### Fixes - Fixed an issue where `shell.openPath` was not non-blocking as expected. [#​48079](https://redirect.github.com/electron/electron/pull/48079) (Also in [36](https://redirect.github.com/electron/electron/pull/48088), [37](https://redirect.github.com/electron/electron/pull/48088), [38](https://redirect.github.com/electron/electron/pull/48088)) ### [`v35.7.4`](https://redirect.github.com/electron/electron/releases/tag/v35.7.4): electron v35.7.4 [Compare Source](https://redirect.github.com/electron/electron/compare/v35.7.2...v35.7.4) ##### Release Notes for v35.7.4 - Fix ffmpeg generation on Windows non-x64 ### [`v35.7.2`](https://redirect.github.com/electron/electron/releases/tag/v35.7.2): electron v35.7.2 [Compare Source](https://redirect.github.com/electron/electron/compare/v35.7.0...v35.7.2) ##### Release Notes for v35.7.2 ##### Fixes - Fixed an issue where printing PDFs with `webContents.print({ silent: true })` would fail. [#​47645](https://redirect.github.com/electron/electron/pull/47645) (Also in [36](https://redirect.github.com/electron/electron/pull/47624), [37](https://redirect.github.com/electron/electron/pull/47397)) ### [`v35.7.0`](https://redirect.github.com/electron/electron/releases/tag/v35.7.0): electron v35.7.0 [Compare Source](https://redirect.github.com/electron/electron/compare/v35.6.0...v35.7.0) ##### Release Notes for v35.7.0 ##### Other Changes - Updated Node.js to v22.16.0. [#​47213](https://redirect.github.com/electron/electron/pull/47213) ### [`v35.6.0`](https://redirect.github.com/electron/electron/releases/tag/v35.6.0): electron v35.6.0 [Compare Source](https://redirect.github.com/electron/electron/compare/v35.5.1...v35.6.0) ##### Release Notes for v35.6.0 ##### Features - Added support for `--no-experimental-global-navigator` flag. [#​47416](https://redirect.github.com/electron/electron/pull/47416) (Also in [36](https://redirect.github.com/electron/electron/pull/47417), [37](https://redirect.github.com/electron/electron/pull/47418)) - Added support for customizing system accent color and highlighting of active window border. [#​47539](https://redirect.github.com/electron/electron/pull/47539) (Also in [36](https://redirect.github.com/electron/electron/pull/47538), [37](https://redirect.github.com/electron/electron/pull/47537)) ##### Fixes - Fixed a potential crash using `session.clearData` in some circumstances. [#​47410](https://redirect.github.com/electron/electron/pull/47410) (Also in [36](https://redirect.github.com/electron/electron/pull/47411), [37](https://redirect.github.com/electron/electron/pull/47412)) - Fixed an error when importing `electron` for the first time from an ESM module loaded by a CJS module in a packaged app. [#​47344](https://redirect.github.com/electron/electron/pull/47344) (Also in [36](https://redirect.github.com/electron/electron/pull/47343), [37](https://redirect.github.com/electron/electron/pull/47342)) - Fixed an issue where calling `Fetch.continueResponse` via debugger with `WebContentsView` could cause a crash. [#​47443](https://redirect.github.com/electron/electron/pull/47443) (Also in [36](https://redirect.github.com/electron/electron/pull/47442), [37](https://redirect.github.com/electron/electron/pull/47444)) - Fixed an issue where utility processes could leak file handles. [#​47542](https://redirect.github.com/electron/electron/pull/47542) (Also in [36](https://redirect.github.com/electron/electron/pull/47541), [37](https://redirect.github.com/electron/electron/pull/47543)) - Partially fixes an issue with printing a PDF via `webContents.print()` where the callback would not be called. [#​47399](https://redirect.github.com/electron/electron/pull/47399) (Also in [36](https://redirect.github.com/electron/electron/pull/47400), [37](https://redirect.github.com/electron/electron/pull/47398)) ##### Other Changes - Backported fix for [`4206375`](https://redirect.github.com/electron/electron/commit/420637585). [#​47369](https://redirect.github.com/electron/electron/pull/47369)
--- ### Configuration 📅 **Schedule**: Branch creation - "" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/toeverything/AFFiNE). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index ae8b7ef24e..4ce3c4d09e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20804,15 +20804,15 @@ __metadata: linkType: hard "electron@npm:^35.0.0": - version: 35.5.1 - resolution: "electron@npm:35.5.1" + version: 35.7.5 + resolution: "electron@npm:35.7.5" dependencies: "@electron/get": "npm:^2.0.0" "@types/node": "npm:^22.7.7" extract-zip: "npm:^2.0.1" bin: electron: cli.js - checksum: 10/765752c94c3bea799f62fb0a75049a10452ff97e791a96111f36b97293ffed9240b27dbc083c01f7a2c7172e84b6b394b07c9aaf91d57783958b2adb4e570579 + checksum: 10/f3757f0b6f21ddd5ebf8b83becdaa3e47dc13473e5375e6e6aee638d7029e73d08d6a4170b37ad8c594057da139e7cdf4c8b82b70c2c1ad0306abdcc274c5fee languageName: node linkType: hard From 93554304e23e5406fd006de591e778d5348d539a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 03:05:12 +0800 Subject: [PATCH 12/28] chore: bump dompurify from 3.1.6 to 3.2.7 (#13622) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.6 to 3.2.7.
Release notes

Sourced from dompurify's releases.

DOMPurify 3.2.7

  • Added new attributes and elements to default allow-list, thanks @​elrion018
  • Added tagName parameter to custom element attributeNameCheck, thanks @​nelstrom
  • Added better check for animated href attributes, thanks @​llamakko
  • Updated and improved the bundled types, thanks @​ssi02014
  • Updated several tests to better align with new browser encoding behaviors
  • Improved the handling of potentially risky content inside CDATA elements, thanks @​securityMB & @​terjanq
  • Improved the regular expression for raw-text elements to cover textareas, thanks @​securityMB & @​terjanq

DOMPurify 3.2.6

DOMPurify 3.2.5

  • Added a check to the mXSS detection regex to be more strict, thanks @​masatokinugawa
  • Added ESM type imports in source, removes patch function, thanks @​donmccurdy
  • Added script to verify various TypeScript configurations, thanks @​reduckted
  • Added more modern browsers to the Karma launchers list
  • Added Node 23.x to tested runtimes, removed Node 17.x
  • Fixed the generation of source maps, thanks @​reduckted
  • Fixed an unexpected behavior with ALLOWED_URI_REGEXP using the 'g' flag, thanks @​hhk-png
  • Fixed a few typos in the README file

DOMPurify 3.2.4

  • Fixed a conditional and config dependent mXSS-style bypass reported by @​nsysean
  • Added a new feature to allow specific hook removal, thanks @​davecardwell
  • Added purify.js and purify.min.js to exports, thanks @​Aetherinox
  • Added better logic in case no window object is president, thanks @​yehuya
  • Updated some dependencies called out by dependabot
  • Updated license files etc to show the correct year

DOMPurify 3.2.3

DOMPurify 3.2.2

  • Fixed a possible bypass in case a rather specific config for custom elements is set, thanks @​yaniv-git
  • Fixed several minor issues with the type definitions, thanks again @​reduckted
  • Fixed a minor issue with the types reference for trusted types, thanks @​reduckted
  • Fixed a minor problem with the template detection regex on some systems, thanks @​svdb99

DOMPurify 3.2.1

... (truncated)

Commits
  • eaa0bdb Merge pull request #1144 from cure53/main
  • f712593 fix: removed a possibly dossy regex
  • eb9b3b6 Merge branch 'main' of github.com:cure53/DOMPurify
  • ce006f7 chore: Preparing 3.2.7 release
  • ef0e0cb chore: Preparing 3.2.6 release
  • 2f09cd3 Update README.md
  • 6a795bc Merge pull request #1142 from cure53/dependabot/github_actions/actions/setup-...
  • 2458bbd build(deps): bump actions/setup-node from 4 to 5
  • e43d3f3 Merge pull request #1136 from cure53/dependabot/github_actions/actions/checko...
  • 6f5be37 build(deps): bump actions/checkout from 4 to 5
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dompurify&package-manager=npm_and_yarn&previous-version=3.1.6&new-version=3.2.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/toeverything/AFFiNE/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4ce3c4d09e..98360bebf0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20509,14 +20509,14 @@ __metadata: linkType: hard "dompurify@npm:^3.2.4": - version: 3.2.6 - resolution: "dompurify@npm:3.2.6" + version: 3.2.7 + resolution: "dompurify@npm:3.2.7" dependencies: "@types/trusted-types": "npm:^2.0.7" dependenciesMeta: "@types/trusted-types": optional: true - checksum: 10/b91631ed0e4d17fae950ef53613cc009ed7e73adc43ac94a41dd52f35483f7538d13caebdafa7626e0da145fc8184e7ac7935f14f25b7e841b32fda777e40447 + checksum: 10/51b7866fb834ee62d6c415f41ece5ce11db7b463f60a822932a1f832573a40b98be7715550298690e7647988fbe086db1098bda9b10548b3166fc975eb9bd849 languageName: node linkType: hard From 195864fc881c157d85669c2362c85e825de6c240 Mon Sep 17 00:00:00 2001 From: Cats Juice Date: Mon, 22 Sep 2025 18:24:11 +0800 Subject: [PATCH 13/28] feat(core): edit icon in navigation panel (#13595) ## Summary by CodeRabbit - **New Features** - Rename dialog now edits per-item explorer icons (emoji or custom) and can skip name-change callbacks. Doc icon picker added to the editor with localized "Add icon" placeholder and readonly rendering. Icon editor supports fallbacks, trigger variants, and improved input/test-id wiring. - **Style** - Updated icon picker and trigger sizing and placeholder visuals; title/icon layout adjustments. - **Chores** - Explorer icon storage and module added to persist and serve icons across the app. --- .../fragments/doc-title/src/doc-title.ts | 2 + .../icon-name-editor/icon-name-editor.css.ts | 12 +- .../icon-name-editor.stories.tsx | 4 +- .../ui/icon-name-editor/icon-name-editor.tsx | 69 ++++++++--- .../block-suite-editor/doc-icon-picker.css.ts | 31 +++++ .../block-suite-editor/doc-icon-picker.tsx | 82 +++++++++++++ .../block-suite-editor/lit-adaper.tsx | 4 + .../nodes/collection/index.tsx | 4 + .../nodes/collection/operations.tsx | 8 +- .../navigation-panel/nodes/doc/index.tsx | 4 + .../navigation-panel/nodes/folder/index.tsx | 1 + .../navigation-panel/nodes/tag/index.tsx | 4 + .../navigation-panel/sections/tags/index.tsx | 12 +- .../components/navigation-panel/tree/node.tsx | 114 +++++++++++++----- .../core/src/modules/db/schema/schema.ts | 12 ++ .../src/modules/doc-display-meta/index.ts | 4 +- .../services/doc-display-meta.ts | 54 ++++----- .../core/src/modules/explorer-icon/index.ts | 13 ++ .../explorer-icon/services/explorer-icon.ts | 21 ++++ .../explorer-icon/store/explorer-icon.ts | 39 ++++++ packages/frontend/core/src/modules/index.ts | 2 + .../core/src/utils/extract-emoji-icon.ts | 3 + packages/frontend/i18n/src/i18n.gen.ts | 4 + packages/frontend/i18n/src/resources/en.json | 1 + tests/affine-local/e2e/links.spec.ts | 82 ++++++------- 25 files changed, 450 insertions(+), 136 deletions(-) create mode 100644 packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.css.ts create mode 100644 packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.tsx create mode 100644 packages/frontend/core/src/modules/explorer-icon/index.ts create mode 100644 packages/frontend/core/src/modules/explorer-icon/services/explorer-icon.ts create mode 100644 packages/frontend/core/src/modules/explorer-icon/store/explorer-icon.ts diff --git a/blocksuite/affine/fragments/doc-title/src/doc-title.ts b/blocksuite/affine/fragments/doc-title/src/doc-title.ts index acf3baab4d..61c966c580 100644 --- a/blocksuite/affine/fragments/doc-title/src/doc-title.ts +++ b/blocksuite/affine/fragments/doc-title/src/doc-title.ts @@ -19,6 +19,7 @@ const DOC_BLOCK_CHILD_PADDING = 24; export class DocTitle extends WithDisposable(ShadowlessElement) { static override styles = css` + .doc-icon-container, .doc-title-container { box-sizing: border-box; font-family: var(--affine-font-family); @@ -49,6 +50,7 @@ export class DocTitle extends WithDisposable(ShadowlessElement) { /* Extra small devices (phones, 640px and down) */ @container viewport (width <= 640px) { + .doc-icon-container, .doc-title-container { padding-left: ${DOC_BLOCK_CHILD_PADDING}px; padding-right: ${DOC_BLOCK_CHILD_PADDING}px; diff --git a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts index 1446acdc04..01431acbca 100644 --- a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts +++ b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts @@ -14,13 +14,19 @@ export const contentRoot = style({ }); export const iconPicker = style({ - border: `1px solid ${cssVarV2.layer.insideBorder.border}`, - width: 32, - height: 32, padding: 0, +}); +globalStyle(`${iconPicker} span:has(svg)`, { + lineHeight: 0, +}); + +export const iconNamePickerIcon = style({ flexShrink: 0, fontSize: 24, borderRadius: 4, + width: 32, + height: 32, + border: `1px solid ${cssVarV2.layer.insideBorder.border}`, selectors: { '&[data-icon-type="emoji"]': { fontSize: 20, diff --git a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx index 514b92f58a..56f2f696f4 100644 --- a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx +++ b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx @@ -16,10 +16,10 @@ export default { } satisfies Meta; export const Basic: StoryFn = () => { - const [icon, setIcon] = useState('👋'); + const [icon, setIcon] = useState('👋'); const [name, setName] = useState('Hello'); - const handleIconChange = useCallback((_: IconType, icon: string) => { + const handleIconChange = useCallback((_?: IconType, icon?: string) => { setIcon(icon); }, []); const handleNameChange = useCallback((name: string) => { diff --git a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.tsx b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.tsx index f477a933fe..e177e66853 100644 --- a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.tsx +++ b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.tsx @@ -4,7 +4,7 @@ import clsx from 'clsx'; import { useTheme } from 'next-themes'; import { type ReactNode, useCallback, useState } from 'react'; -import { Button } from '../button'; +import { Button, type ButtonProps } from '../button'; import Input from '../input'; import { Menu, type MenuProps } from '../menu'; import * as styles from './icon-name-editor.css'; @@ -12,11 +12,11 @@ import * as styles from './icon-name-editor.css'; export type IconType = 'emoji' | 'affine-icon' | 'blob'; export interface IconEditorProps { - iconType: IconType; - icon: string; + iconType?: IconType; + icon?: string; closeAfterSelect?: boolean; iconPlaceholder?: ReactNode; - onIconChange?: (type: IconType, icon: string) => void; + onIconChange?: (type?: IconType, icon?: string) => void; triggerClassName?: string; } @@ -24,6 +24,8 @@ export interface IconAndNameEditorContentProps extends IconEditorProps { name: string; namePlaceholder?: string; onNameChange?: (name: string) => void; + onEnter?: () => void; + inputTestId?: string; } export interface IconAndNameEditorMenuProps @@ -33,20 +35,23 @@ export interface IconAndNameEditorMenuProps onOpenChange?: (open: boolean) => void; width?: string | number; + skipIfNotChanged?: boolean; } -const IconRenderer = ({ +export const IconRenderer = ({ iconType, icon, + fallback, }: { iconType: IconType; icon: string; + fallback?: ReactNode; }) => { switch (iconType) { case 'emoji': - return
{icon}
; + return
{icon ?? fallback}
; default: - throw new Error(`Unsupported icon type: ${iconType}`); + return
{fallback}
; } }; @@ -59,9 +64,11 @@ export const IconEditor = ({ onIconChange, alignOffset, sideOffset = 4, + triggerVariant, }: IconEditorProps & { alignOffset?: number; sideOffset?: number; + triggerVariant?: ButtonProps['variant']; }) => { const [isPickerOpen, setIsPickerOpen] = useState(false); const { resolvedTheme } = useTheme(); @@ -99,11 +106,18 @@ export const IconEditor = ({ } > + + +
+ {activePanel === 'Emoji' ? ( + + ) : activePanel === 'Icons' ? ( + + ) : null} +
+ + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/index.ts b/packages/frontend/component/src/ui/icon-picker/index.ts new file mode 100644 index 0000000000..1fd5d61e59 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/index.ts @@ -0,0 +1 @@ +export * from './icon-picker'; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/affine-icon/affine-icon-picker.css.ts b/packages/frontend/component/src/ui/icon-picker/picker/affine-icon/affine-icon-picker.css.ts new file mode 100644 index 0000000000..36ab18bc3d --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/affine-icon/affine-icon-picker.css.ts @@ -0,0 +1,17 @@ +import { style } from '@vanilla-extract/css'; + +export const colorList = style({ + display: 'flex', + gap: 4, +}); + +export const colorItem = style({ + padding: 2, +}); + +export const colorDot = style({ + width: '1em', + height: '1em', + borderRadius: '50%', + background: 'currentColor', +}); diff --git a/packages/frontend/component/src/ui/icon-picker/picker/affine-icon/affine-icon-picker.tsx b/packages/frontend/component/src/ui/icon-picker/picker/affine-icon/affine-icon-picker.tsx new file mode 100644 index 0000000000..673bb3973b --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/affine-icon/affine-icon-picker.tsx @@ -0,0 +1,201 @@ +import keywords from '@blocksuite/icons/keywords/en.json'; +import * as allIcons from '@blocksuite/icons/rc'; +import { cssVarV2 } from '@toeverything/theme/v2'; +import { startTransition, useCallback, useEffect, useState } from 'react'; + +import { IconButton } from '../../../button'; +import Input from '../../../input'; +import { Menu } from '../../../menu'; +import { Scrollable } from '../../../scrollbar'; +import { AffineIconRenderer } from '../../renderer/affine-icon'; +import * as pickerStyles from '../picker.css'; +import * as styles from './affine-icon-picker.css'; + +type Icon = { + name: string; + keywords: string[]; +}; + +const icons = keywords['Emoji Panel'] as Icon[]; + +const colorList: string[] = [ + cssVarV2.block.callout.icon.red, + cssVarV2.block.callout.icon.orange, + cssVarV2.block.callout.icon.yellow, + cssVarV2.block.callout.icon.green, + cssVarV2.block.callout.icon.teal, + cssVarV2.block.callout.icon.blue, + cssVarV2.block.callout.icon.purple, + cssVarV2.block.callout.icon.magenta, + cssVarV2.block.callout.icon.grey, +]; + +const useRecentIcons = () => { + const [recentIcons, setRecentIcons] = useState>([]); + + useEffect(() => { + const recentIcons = localStorage.getItem('recentIcons'); + setRecentIcons(recentIcons ? recentIcons.split(',') : []); + }, []); + + const add = useCallback((icon: string) => { + setRecentIcons(prevRecentIcons => { + const newRecentIcons = [ + icon, + ...prevRecentIcons.filter(e => e !== icon), + ].slice(0, 10); + localStorage.setItem('recentIcons', newRecentIcons.join(',')); + return newRecentIcons; + }); + }, []); + + return { + recentIcons, + add, + }; +}; + +export const AffineIconPicker = ({ + onSelect, +}: { + onSelect?: (icon: string, color: string) => void; +}) => { + const [filteredIcons, setFilteredIcons] = useState([]); + const [keyword, setKeyword] = useState(''); + const [color, setColor] = useState(cssVarV2.block.callout.icon.blue); + + const { recentIcons, add: addRecentIcon } = useRecentIcons(); + + useEffect(() => { + startTransition(() => { + if (!keyword) { + setFilteredIcons(icons); + return; + } + + setFilteredIcons( + icons.filter(icon => + icon.keywords.some(kw => kw.includes(keyword.toLowerCase())) + ) + ); + }); + }, [keyword]); + + const handleIconSelect = useCallback( + (icon: string) => { + addRecentIcon(icon); + onSelect?.(icon, color); + }, + [addRecentIcon, onSelect, color] + ); + + return ( +
+ {/* Search */} +
+ + +
+ } + placeholder="Filter..." + /> + + {/* Color Picker */} + + {colorList.map(color => ( + + } + onClick={() => setColor(color)} + /> + ))} + + } + > + + } + /> + + + + {/* Content */} + + + {/* Recent */} + {recentIcons.length ? ( +
+
+ Recent +
+
+ {recentIcons.map(iconName => ( + + } + onClick={() => handleIconSelect(iconName)} + /> + ))} +
+
+ ) : null} + + {/* Groups */} +
+
+ Icons +
+
+ {filteredIcons.map(icon => { + return ( + + } + onClick={() => handleIconSelect(icon.name)} + /> + ); + })} +
+
+
+ +
+ + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/constants.ts b/packages/frontend/component/src/ui/icon-picker/picker/emoji/constants.ts new file mode 100644 index 0000000000..8255ef6be7 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/constants.ts @@ -0,0 +1,43 @@ +import type { ComponentType, SVGProps } from 'react'; + +import { ActivityIcon } from './icons/activity'; +import { AnimalIcon } from './icons/animal'; +import { FlagIcon } from './icons/flag'; +import { FoodIcon } from './icons/food'; +import { ObjectIcon } from './icons/object'; +import { SmileIcon } from './icons/smile'; +import { SymbolIcon } from './icons/symbol'; +import { TravelIcon } from './icons/travel'; + +export type GroupName = + | 'Smileys & People' + | 'Animals & Nature' + | 'Food & Drink' + | 'Activity' + | 'Travel & Places' + | 'Objects' + | 'Symbols' + | 'Flags'; +export const GROUPS: GroupName[] = [ + 'Smileys & People', + 'Animals & Nature', + 'Food & Drink', + 'Activity', + 'Travel & Places', + 'Objects', + 'Symbols', + 'Flags', +]; +export const GROUP_ICON_MAP: Record< + GroupName, + ComponentType> +> = { + 'Smileys & People': SmileIcon, + 'Animals & Nature': AnimalIcon, + 'Food & Drink': FoodIcon, + Activity: ActivityIcon, + 'Travel & Places': TravelIcon, + Objects: ObjectIcon, + Symbols: SymbolIcon, + Flags: FlagIcon, +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/data/en.json b/packages/frontend/component/src/ui/icon-picker/picker/emoji/data/en.json new file mode 100644 index 0000000000..c81d71e41d --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/data/en.json @@ -0,0 +1,35020 @@ +[ + { + "name": "Smileys & People", + "emojis": [ + { + "group": 0, + "hexcode": "1F600", + "label": "grinning face", + "order": 1, + "tags": [ + "cheerful", + "cheery", + "face", + "grin", + "grinning", + "happy", + "laugh", + "nice", + "smile", + "smiling", + "teeth" + ], + "unicode": "😀" + }, + { + "group": 0, + "hexcode": "1F603", + "label": "grinning face with big eyes", + "order": 2, + "tags": [ + "awesome", + "big", + "eyes", + "face", + "grin", + "grinning", + "happy", + "mouth", + "open", + "smile", + "smiling", + "teeth", + "yay" + ], + "unicode": "😃" + }, + { + "group": 0, + "hexcode": "1F604", + "label": "grinning face with smiling eyes", + "order": 3, + "tags": [ + "eye", + "eyes", + "face", + "grin", + "grinning", + "happy", + "laugh", + "lol", + "mouth", + "open", + "smile", + "smiling" + ], + "unicode": "😄", + "emoticon": ":D" + }, + { + "group": 0, + "hexcode": "1F601", + "label": "beaming face with smiling eyes", + "order": 4, + "tags": [ + "beaming", + "eye", + "eyes", + "face", + "grin", + "grinning", + "happy", + "nice", + "smile", + "smiling", + "teeth" + ], + "unicode": "😁" + }, + { + "group": 0, + "hexcode": "1F606", + "label": "grinning squinting face", + "order": 5, + "tags": [ + "closed", + "eyes", + "face", + "grinning", + "haha", + "hahaha", + "happy", + "laugh", + "lol", + "mouth", + "open", + "rofl", + "smile", + "smiling", + "squinting" + ], + "unicode": "😆", + "emoticon": ["xD", "XD"] + }, + { + "group": 0, + "hexcode": "1F605", + "label": "grinning face with sweat", + "order": 6, + "tags": [ + "cold", + "dejected", + "excited", + "face", + "grinning", + "mouth", + "nervous", + "open", + "smile", + "smiling", + "stress", + "stressed", + "sweat" + ], + "unicode": "😅" + }, + { + "group": 0, + "hexcode": "1F923", + "label": "rolling on the floor laughing", + "order": 7, + "tags": [ + "crying", + "face", + "floor", + "funny", + "haha", + "happy", + "hehe", + "hilarious", + "joy", + "laugh", + "lmao", + "lol", + "rofl", + "roflmao", + "rolling", + "tear" + ], + "unicode": "🤣", + "emoticon": ":'D" + }, + { + "group": 0, + "hexcode": "1F602", + "label": "face with tears of joy", + "order": 8, + "tags": [ + "crying", + "face", + "feels", + "funny", + "haha", + "happy", + "hehe", + "hilarious", + "joy", + "laugh", + "lmao", + "lol", + "rofl", + "roflmao", + "tear" + ], + "unicode": "😂", + "emoticon": ":')" + }, + { + "group": 0, + "hexcode": "1F642", + "label": "slightly smiling face", + "order": 9, + "tags": ["face", "happy", "slightly", "smile", "smiling"], + "unicode": "🙂", + "emoticon": ":)" + }, + { + "group": 0, + "hexcode": "1F643", + "label": "upside-down face", + "order": 10, + "tags": ["face", "hehe", "smile", "upside-down"], + "unicode": "🙃" + }, + { + "group": 0, + "hexcode": "1FAE0", + "label": "melting face", + "order": 11, + "tags": [ + "disappear", + "dissolve", + "embarrassed", + "face", + "haha", + "heat", + "hot", + "liquid", + "lol", + "melt", + "melting", + "sarcasm", + "sarcastic" + ], + "unicode": "🫠" + }, + { + "group": 0, + "hexcode": "1F609", + "label": "winking face", + "order": 12, + "tags": [ + "face", + "flirt", + "heartbreaker", + "sexy", + "slide", + "tease", + "wink", + "winking", + "winks" + ], + "unicode": "😉", + "emoticon": ";)" + }, + { + "group": 0, + "hexcode": "1F60A", + "label": "smiling face with smiling eyes", + "order": 13, + "tags": [ + "blush", + "eye", + "eyes", + "face", + "glad", + "satisfied", + "smile", + "smiling" + ], + "unicode": "😊", + "emoticon": ":>" + }, + { + "group": 0, + "hexcode": "1F607", + "label": "smiling face with halo", + "order": 14, + "tags": [ + "angel", + "angelic", + "angels", + "blessed", + "face", + "fairy", + "fairytale", + "fantasy", + "halo", + "happy", + "innocent", + "peaceful", + "smile", + "smiling", + "spirit", + "tale" + ], + "unicode": "😇", + "emoticon": ["o:)", "O:)"] + }, + { + "group": 0, + "hexcode": "1F970", + "label": "smiling face with hearts", + "order": 15, + "tags": [ + "3", + "adore", + "crush", + "face", + "heart", + "hearts", + "ily", + "love", + "romance", + "smile", + "smiling", + "you" + ], + "unicode": "🥰" + }, + { + "group": 0, + "hexcode": "1F60D", + "label": "smiling face with heart-eyes", + "order": 16, + "tags": [ + "143", + "bae", + "eye", + "face", + "feels", + "heart-eyes", + "hearts", + "ily", + "kisses", + "love", + "romance", + "romantic", + "smile", + "xoxo" + ], + "unicode": "😍" + }, + { + "group": 0, + "hexcode": "1F929", + "label": "star-struck", + "order": 17, + "tags": [ + "excited", + "eyes", + "face", + "grinning", + "smile", + "star", + "starry-eyed", + "wow" + ], + "unicode": "🤩" + }, + { + "group": 0, + "hexcode": "1F618", + "label": "face blowing a kiss", + "order": 18, + "tags": [ + "adorbs", + "bae", + "blowing", + "face", + "flirt", + "heart", + "ily", + "kiss", + "love", + "lover", + "miss", + "muah", + "romantic", + "smooch", + "xoxo", + "you" + ], + "unicode": "😘", + "emoticon": [":x", ":X"] + }, + { + "group": 0, + "hexcode": "1F617", + "label": "kissing face", + "order": 19, + "tags": [ + "143", + "date", + "dating", + "face", + "flirt", + "ily", + "kiss", + "love", + "smooch", + "smooches", + "xoxo", + "you" + ], + "unicode": "😗" + }, + { + "group": 0, + "hexcode": "263A", + "label": "smiling face", + "order": 21, + "tags": ["face", "happy", "outlined", "relaxed", "smile", "smiling"], + "unicode": "☺️" + }, + { + "group": 0, + "hexcode": "1F61A", + "label": "kissing face with closed eyes", + "order": 22, + "tags": [ + "143", + "bae", + "blush", + "closed", + "date", + "dating", + "eye", + "eyes", + "face", + "flirt", + "ily", + "kisses", + "kissing", + "smooches", + "xoxo" + ], + "unicode": "😚", + "emoticon": ":*" + }, + { + "group": 0, + "hexcode": "1F619", + "label": "kissing face with smiling eyes", + "order": 23, + "tags": [ + "143", + "closed", + "date", + "dating", + "eye", + "eyes", + "face", + "flirt", + "ily", + "kiss", + "kisses", + "kissing", + "love", + "night", + "smile", + "smiling" + ], + "unicode": "😙" + }, + { + "group": 0, + "hexcode": "1F972", + "label": "smiling face with tear", + "order": 24, + "tags": [ + "face", + "glad", + "grateful", + "happy", + "joy", + "pain", + "proud", + "relieved", + "smile", + "smiley", + "smiling", + "tear", + "touched" + ], + "unicode": "🥲" + }, + { + "group": 0, + "hexcode": "1F60B", + "label": "face savoring food", + "order": 25, + "tags": [ + "delicious", + "eat", + "face", + "food", + "full", + "hungry", + "savor", + "smile", + "smiling", + "tasty", + "um", + "yum", + "yummy" + ], + "unicode": "😋" + }, + { + "group": 0, + "hexcode": "1F61B", + "label": "face with tongue", + "order": 26, + "tags": [ + "awesome", + "cool", + "face", + "nice", + "party", + "stuck-out", + "sweet", + "tongue" + ], + "unicode": "😛", + "emoticon": [":p", ":P"] + }, + { + "group": 0, + "hexcode": "1F61C", + "label": "winking face with tongue", + "order": 27, + "tags": [ + "crazy", + "epic", + "eye", + "face", + "funny", + "joke", + "loopy", + "nutty", + "party", + "stuck-out", + "tongue", + "wacky", + "weirdo", + "wink", + "winking", + "yolo" + ], + "unicode": "😜", + "emoticon": [";p", ";P"] + }, + { + "group": 0, + "hexcode": "1F92A", + "label": "zany face", + "order": 28, + "tags": [ + "crazy", + "eye", + "eyes", + "face", + "goofy", + "large", + "small", + "zany" + ], + "unicode": "🤪" + }, + { + "group": 0, + "hexcode": "1F61D", + "label": "squinting face with tongue", + "order": 29, + "tags": [ + "closed", + "eye", + "eyes", + "face", + "gross", + "horrible", + "omg", + "squinting", + "stuck-out", + "taste", + "tongue", + "whatever", + "yolo" + ], + "unicode": "😝", + "emoticon": ["xp", "xP", "XP"] + }, + { + "group": 0, + "hexcode": "1F911", + "label": "money-mouth face", + "order": 30, + "tags": ["face", "money", "money-mouth", "mouth", "paid"], + "unicode": "🤑" + }, + { + "group": 0, + "hexcode": "1F917", + "label": "smiling face with open hands", + "order": 31, + "tags": ["face", "hands", "hug", "hugging", "open", "smiling"], + "unicode": "🤗" + }, + { + "group": 0, + "hexcode": "1F92D", + "label": "face with hand over mouth", + "order": 32, + "tags": [ + "face", + "giggle", + "giggling", + "hand", + "mouth", + "oops", + "realization", + "secret", + "shock", + "sudden", + "surprise", + "whoops" + ], + "unicode": "🤭" + }, + { + "group": 0, + "hexcode": "1FAE2", + "label": "face with open eyes and hand over mouth", + "order": 33, + "tags": [ + "amazement", + "awe", + "disbelief", + "embarrass", + "eyes", + "face", + "gasp", + "hand", + "mouth", + "omg", + "open", + "over", + "quiet", + "scared", + "shock", + "surprise" + ], + "unicode": "🫢" + }, + { + "group": 0, + "hexcode": "1FAE3", + "label": "face with peeking eye", + "order": 34, + "tags": [ + "captivated", + "embarrass", + "eye", + "face", + "hide", + "hiding", + "peek", + "peeking", + "peep", + "scared", + "shy", + "stare" + ], + "unicode": "🫣" + }, + { + "group": 0, + "hexcode": "1F92B", + "label": "shushing face", + "order": 35, + "tags": ["face", "quiet", "shh", "shush", "shushing"], + "unicode": "🤫" + }, + { + "group": 0, + "hexcode": "1F914", + "label": "thinking face", + "order": 36, + "tags": [ + "chin", + "consider", + "face", + "hmm", + "ponder", + "pondering", + "thinking", + "wondering" + ], + "unicode": "🤔", + "emoticon": [":l", ":L"] + }, + { + "group": 0, + "hexcode": "1FAE1", + "label": "saluting face", + "order": 37, + "tags": [ + "face", + "good", + "luck", + "ma’am", + "ok", + "respect", + "salute", + "saluting", + "sir", + "troops", + "yes" + ], + "unicode": "🫡" + }, + { + "group": 0, + "hexcode": "1F910", + "label": "zipper-mouth face", + "order": 38, + "tags": [ + "face", + "keep", + "mouth", + "quiet", + "secret", + "shut", + "zip", + "zipper", + "zipper-mouth" + ], + "unicode": "🤐", + "emoticon": [":z", ":Z"] + }, + { + "group": 0, + "hexcode": "1F928", + "label": "face with raised eyebrow", + "order": 39, + "tags": [ + "disapproval", + "disbelief", + "distrust", + "emoji", + "eyebrow", + "face", + "hmm", + "mild", + "raised", + "skeptic", + "skeptical", + "skepticism", + "surprise", + "what" + ], + "unicode": "🤨" + }, + { + "group": 0, + "hexcode": "1F610", + "label": "neutral face", + "order": 40, + "tags": [ + "awkward", + "blank", + "deadpan", + "expressionless", + "face", + "fine", + "jealous", + "meh", + "neutral", + "oh", + "shade", + "straight", + "unamused", + "unhappy", + "unimpressed", + "whatever" + ], + "unicode": "😐️", + "emoticon": ":|" + }, + { + "group": 0, + "hexcode": "1F611", + "label": "expressionless face", + "order": 41, + "tags": [ + "awkward", + "dead", + "expressionless", + "face", + "fine", + "inexpressive", + "jealous", + "meh", + "not", + "oh", + "omg", + "straight", + "uh", + "unhappy", + "unimpressed", + "whatever" + ], + "unicode": "😑" + }, + { + "group": 0, + "hexcode": "1F636", + "label": "face without mouth", + "order": 42, + "tags": [ + "awkward", + "blank", + "expressionless", + "face", + "mouth", + "mouthless", + "mute", + "quiet", + "secret", + "silence", + "silent", + "speechless" + ], + "unicode": "😶", + "emoticon": ":#" + }, + { + "group": 0, + "hexcode": "1FAE5", + "label": "dotted line face", + "order": 43, + "tags": [ + "depressed", + "disappear", + "dotted", + "face", + "hidden", + "hide", + "introvert", + "invisible", + "line", + "meh", + "whatever", + "wtv" + ], + "unicode": "🫥" + }, + { + "group": 0, + "hexcode": "1F636-200D-1F32B-FE0F", + "label": "face in clouds", + "order": 44, + "tags": ["absentminded", "clouds", "face", "fog", "head"], + "unicode": "😶‍🌫️" + }, + { + "group": 0, + "hexcode": "1F60F", + "label": "smirking face", + "order": 46, + "tags": [ + "boss", + "dapper", + "face", + "flirt", + "homie", + "kidding", + "leer", + "shade", + "slick", + "sly", + "smirk", + "smug", + "snicker", + "suave", + "suspicious", + "swag" + ], + "unicode": "😏", + "emoticon": ":j" + }, + { + "group": 0, + "hexcode": "1F612", + "label": "unamused face", + "order": 47, + "tags": [ + "...", + "bored", + "face", + "fine", + "jealous", + "jel", + "jelly", + "pissed", + "smh", + "ugh", + "uhh", + "unamused", + "unhappy", + "weird", + "whatever" + ], + "unicode": "😒", + "emoticon": ":?" + }, + { + "group": 0, + "hexcode": "1F644", + "label": "face with rolling eyes", + "order": 48, + "tags": [ + "eyeroll", + "eyes", + "face", + "rolling", + "shade", + "ugh", + "whatever" + ], + "unicode": "🙄" + }, + { + "group": 0, + "hexcode": "1F62C", + "label": "grimacing face", + "order": 49, + "tags": [ + "awk", + "awkward", + "dentist", + "face", + "grimace", + "grimacing", + "grinning", + "smile", + "smiling" + ], + "unicode": "😬", + "emoticon": "8D" + }, + { + "group": 0, + "hexcode": "1F62E-200D-1F4A8", + "label": "face exhaling", + "order": 50, + "tags": [ + "blow", + "blowing", + "exhale", + "exhaling", + "exhausted", + "face", + "gasp", + "groan", + "relief", + "sigh", + "smiley", + "smoke", + "whisper", + "whistle" + ], + "unicode": "😮‍💨" + }, + { + "group": 0, + "hexcode": "1F925", + "label": "lying face", + "order": 51, + "tags": ["face", "liar", "lie", "lying", "pinocchio"], + "unicode": "🤥" + }, + { + "group": 0, + "hexcode": "1FAE8", + "label": "shaking face", + "order": 52, + "tags": [ + "crazy", + "daze", + "earthquake", + "face", + "omg", + "panic", + "shaking", + "shock", + "surprise", + "vibrate", + "whoa", + "wow" + ], + "unicode": "🫨" + }, + { + "group": 0, + "hexcode": "1F642-200D-2194-FE0F", + "label": "head shaking horizontally", + "order": 53, + "tags": ["head", "horizontally", "no", "shake", "shaking"], + "unicode": "🙂‍↔️" + }, + { + "group": 0, + "hexcode": "1F642-200D-2195-FE0F", + "label": "head shaking vertically", + "order": 55, + "tags": ["head", "nod", "shaking", "vertically", "yes"], + "unicode": "🙂‍↕️" + }, + { + "group": 0, + "hexcode": "1F60C", + "label": "relieved face", + "order": 57, + "tags": ["calm", "face", "peace", "relief", "relieved", "zen"], + "unicode": "😌" + }, + { + "group": 0, + "hexcode": "1F614", + "label": "pensive face", + "order": 58, + "tags": [ + "awful", + "bored", + "dejected", + "died", + "disappointed", + "face", + "losing", + "lost", + "pensive", + "sad", + "sucks" + ], + "unicode": "😔" + }, + { + "group": 0, + "hexcode": "1F62A", + "label": "sleepy face", + "order": 59, + "tags": [ + "crying", + "face", + "good", + "night", + "sad", + "sleep", + "sleeping", + "sleepy", + "tired" + ], + "unicode": "😪" + }, + { + "group": 0, + "hexcode": "1F924", + "label": "drooling face", + "order": 60, + "tags": ["drooling", "face"], + "unicode": "🤤" + }, + { + "group": 0, + "hexcode": "1F634", + "label": "sleeping face", + "order": 61, + "tags": [ + "bed", + "bedtime", + "face", + "good", + "goodnight", + "nap", + "night", + "sleep", + "sleeping", + "tired", + "whatever", + "yawn", + "zzz" + ], + "unicode": "😴" + }, + { + "group": 0, + "hexcode": "1FAE9", + "label": "face with bags under eyes", + "order": 62, + "tags": [ + "bags", + "bored", + "exhausted", + "eyes", + "face", + "fatigued", + "late", + "sleepy", + "tired", + "weary" + ], + "unicode": "🫩" + }, + { + "group": 0, + "hexcode": "1F637", + "label": "face with medical mask", + "order": 63, + "tags": [ + "cold", + "dentist", + "dermatologist", + "doctor", + "dr", + "face", + "germs", + "mask", + "medical", + "medicine", + "sick" + ], + "unicode": "😷" + }, + { + "group": 0, + "hexcode": "1F912", + "label": "face with thermometer", + "order": 64, + "tags": ["face", "ill", "sick", "thermometer"], + "unicode": "🤒" + }, + { + "group": 0, + "hexcode": "1F915", + "label": "face with head-bandage", + "order": 65, + "tags": ["bandage", "face", "head-bandage", "hurt", "injury", "ouch"], + "unicode": "🤕" + }, + { + "group": 0, + "hexcode": "1F922", + "label": "nauseated face", + "order": 66, + "tags": ["face", "gross", "nasty", "nauseated", "sick", "vomit"], + "unicode": "🤢", + "emoticon": "%(" + }, + { + "group": 0, + "hexcode": "1F92E", + "label": "face vomiting", + "order": 67, + "tags": [ + "barf", + "ew", + "face", + "gross", + "puke", + "sick", + "spew", + "throw", + "up", + "vomit", + "vomiting" + ], + "unicode": "🤮" + }, + { + "group": 0, + "hexcode": "1F927", + "label": "sneezing face", + "order": 68, + "tags": [ + "face", + "fever", + "flu", + "gesundheit", + "sick", + "sneeze", + "sneezing" + ], + "unicode": "🤧" + }, + { + "group": 0, + "hexcode": "1F975", + "label": "hot face", + "order": 69, + "tags": [ + "dying", + "face", + "feverish", + "heat", + "hot", + "panting", + "red-faced", + "stroke", + "sweating", + "tongue" + ], + "unicode": "🥵" + }, + { + "group": 0, + "hexcode": "1F976", + "label": "cold face", + "order": 70, + "tags": [ + "blue", + "blue-faced", + "cold", + "face", + "freezing", + "frostbite", + "icicles", + "subzero", + "teeth" + ], + "unicode": "🥶" + }, + { + "group": 0, + "hexcode": "1F974", + "label": "woozy face", + "order": 71, + "tags": [ + "dizzy", + "drunk", + "eyes", + "face", + "intoxicated", + "mouth", + "tipsy", + "uneven", + "wavy", + "woozy" + ], + "unicode": "🥴", + "emoticon": ":&" + }, + { + "group": 0, + "hexcode": "1F635", + "label": "face with crossed-out eyes", + "order": 72, + "tags": [ + "crossed-out", + "dead", + "dizzy", + "eyes", + "face", + "feels", + "knocked", + "out", + "sick", + "tired" + ], + "unicode": "😵", + "emoticon": ["xo", "XO"] + }, + { + "group": 0, + "hexcode": "1F635-200D-1F4AB", + "label": "face with spiral eyes", + "order": 73, + "tags": [ + "confused", + "dizzy", + "eyes", + "face", + "hypnotized", + "omg", + "smiley", + "spiral", + "trouble", + "whoa", + "woah", + "woozy" + ], + "unicode": "😵‍💫" + }, + { + "group": 0, + "hexcode": "1F92F", + "label": "exploding head", + "order": 74, + "tags": [ + "blown", + "explode", + "exploding", + "head", + "mind", + "mindblown", + "no", + "shocked", + "way" + ], + "unicode": "🤯" + }, + { + "group": 0, + "hexcode": "1F920", + "label": "cowboy hat face", + "order": 75, + "tags": ["cowboy", "cowgirl", "face", "hat"], + "unicode": "🤠" + }, + { + "group": 0, + "hexcode": "1F973", + "label": "partying face", + "order": 76, + "tags": [ + "bday", + "birthday", + "celebrate", + "celebration", + "excited", + "face", + "happy", + "hat", + "hooray", + "horn", + "party", + "partying" + ], + "unicode": "🥳" + }, + { + "group": 0, + "hexcode": "1F978", + "label": "disguised face", + "order": 77, + "tags": [ + "disguise", + "eyebrow", + "face", + "glasses", + "incognito", + "moustache", + "mustache", + "nose", + "person", + "spy", + "tache", + "tash" + ], + "unicode": "🥸" + }, + { + "group": 0, + "hexcode": "1F60E", + "label": "smiling face with sunglasses", + "order": 78, + "tags": [ + "awesome", + "beach", + "bright", + "bro", + "chilling", + "cool", + "face", + "rad", + "relaxed", + "shades", + "slay", + "smile", + "style", + "sunglasses", + "swag", + "win" + ], + "unicode": "😎", + "emoticon": "8)" + }, + { + "group": 0, + "hexcode": "1F913", + "label": "nerd face", + "order": 79, + "tags": [ + "brainy", + "clever", + "expert", + "face", + "geek", + "gifted", + "glasses", + "intelligent", + "nerd", + "smart" + ], + "unicode": "🤓", + "emoticon": ":B" + }, + { + "group": 0, + "hexcode": "1F9D0", + "label": "face with monocle", + "order": 80, + "tags": [ + "classy", + "face", + "fancy", + "monocle", + "rich", + "stuffy", + "wealthy" + ], + "unicode": "🧐" + }, + { + "group": 0, + "hexcode": "1F615", + "label": "confused face", + "order": 81, + "tags": [ + "befuddled", + "confused", + "confusing", + "dunno", + "face", + "frown", + "hm", + "meh", + "not", + "sad", + "sorry", + "sure" + ], + "unicode": "😕", + "emoticon": ":/" + }, + { + "group": 0, + "hexcode": "1FAE4", + "label": "face with diagonal mouth", + "order": 82, + "tags": [ + "confused", + "confusion", + "diagonal", + "disappointed", + "doubt", + "doubtful", + "face", + "frustrated", + "frustration", + "meh", + "mouth", + "skeptical", + "unsure", + "whatever", + "wtv" + ], + "unicode": "🫤" + }, + { + "group": 0, + "hexcode": "1F61F", + "label": "worried face", + "order": 83, + "tags": [ + "anxious", + "butterflies", + "face", + "nerves", + "nervous", + "sad", + "stress", + "stressed", + "surprised", + "worried", + "worry" + ], + "unicode": "😟" + }, + { + "group": 0, + "hexcode": "1F641", + "label": "slightly frowning face", + "order": 84, + "tags": ["face", "frown", "frowning", "sad", "slightly"], + "unicode": "🙁" + }, + { + "group": 0, + "hexcode": "2639", + "label": "frowning face", + "order": 86, + "tags": ["face", "frown", "frowning", "sad"], + "unicode": "☹️", + "emoticon": ":(" + }, + { + "group": 0, + "hexcode": "1F62E", + "label": "face with open mouth", + "order": 87, + "tags": [ + "believe", + "face", + "forgot", + "mouth", + "omg", + "open", + "shocked", + "surprised", + "sympathy", + "unbelievable", + "unreal", + "whoa", + "wow", + "you" + ], + "unicode": "😮" + }, + { + "group": 0, + "hexcode": "1F62F", + "label": "hushed face", + "order": 88, + "tags": [ + "epic", + "face", + "hushed", + "omg", + "stunned", + "surprised", + "whoa", + "woah" + ], + "unicode": "😯" + }, + { + "group": 0, + "hexcode": "1F632", + "label": "astonished face", + "order": 89, + "tags": [ + "astonished", + "cost", + "face", + "no", + "omg", + "shocked", + "totally", + "way" + ], + "unicode": "😲", + "emoticon": [":o", ":O"] + }, + { + "group": 0, + "hexcode": "1F633", + "label": "flushed face", + "order": 90, + "tags": [ + "amazed", + "awkward", + "crazy", + "dazed", + "dead", + "disbelief", + "embarrassed", + "face", + "flushed", + "geez", + "heat", + "hot", + "impressed", + "jeez", + "what", + "wow" + ], + "unicode": "😳", + "emoticon": ":$" + }, + { + "group": 0, + "hexcode": "1F97A", + "label": "pleading face", + "order": 91, + "tags": [ + "begging", + "big", + "eyes", + "face", + "mercy", + "not", + "pleading", + "please", + "pretty", + "puppy", + "sad", + "why" + ], + "unicode": "🥺" + }, + { + "group": 0, + "hexcode": "1F979", + "label": "face holding back tears", + "order": 92, + "tags": [ + "admiration", + "aww", + "back", + "cry", + "embarrassed", + "face", + "feelings", + "grateful", + "gratitude", + "holding", + "joy", + "please", + "proud", + "resist", + "sad", + "tears" + ], + "unicode": "🥹" + }, + { + "group": 0, + "hexcode": "1F626", + "label": "frowning face with open mouth", + "order": 93, + "tags": [ + "caught", + "face", + "frown", + "frowning", + "guard", + "mouth", + "open", + "scared", + "scary", + "surprise", + "what", + "wow" + ], + "unicode": "😦" + }, + { + "group": 0, + "hexcode": "1F627", + "label": "anguished face", + "order": 94, + "tags": [ + "anguished", + "face", + "forgot", + "scared", + "scary", + "stressed", + "surprise", + "unhappy", + "what", + "wow" + ], + "unicode": "😧", + "emoticon": [":s", ":S"] + }, + { + "group": 0, + "hexcode": "1F628", + "label": "fearful face", + "order": 95, + "tags": [ + "afraid", + "anxious", + "blame", + "face", + "fear", + "fearful", + "scared", + "worried" + ], + "unicode": "😨" + }, + { + "group": 0, + "hexcode": "1F630", + "label": "anxious face with sweat", + "order": 96, + "tags": [ + "anxious", + "blue", + "cold", + "eek", + "face", + "mouth", + "nervous", + "open", + "rushed", + "scared", + "sweat", + "yikes" + ], + "unicode": "😰" + }, + { + "group": 0, + "hexcode": "1F625", + "label": "sad but relieved face", + "order": 97, + "tags": [ + "anxious", + "call", + "close", + "complicated", + "disappointed", + "face", + "not", + "relieved", + "sad", + "sweat", + "time", + "whew" + ], + "unicode": "😥" + }, + { + "group": 0, + "hexcode": "1F622", + "label": "crying face", + "order": 98, + "tags": [ + "awful", + "cry", + "crying", + "face", + "feels", + "miss", + "sad", + "tear", + "triste", + "unhappy" + ], + "unicode": "😢", + "emoticon": ":'(" + }, + { + "group": 0, + "hexcode": "1F62D", + "label": "loudly crying face", + "order": 99, + "tags": [ + "bawling", + "cry", + "crying", + "face", + "loudly", + "sad", + "sob", + "tear", + "tears", + "unhappy" + ], + "unicode": "😭", + "emoticon": ":'o" + }, + { + "group": 0, + "hexcode": "1F631", + "label": "face screaming in fear", + "order": 100, + "tags": [ + "epic", + "face", + "fear", + "fearful", + "munch", + "scared", + "scream", + "screamer", + "screaming", + "shocked", + "surprised", + "woah" + ], + "unicode": "😱", + "emoticon": "Dx" + }, + { + "group": 0, + "hexcode": "1F616", + "label": "confounded face", + "order": 101, + "tags": [ + "annoyed", + "confounded", + "confused", + "cringe", + "distraught", + "face", + "feels", + "frustrated", + "mad", + "sad" + ], + "unicode": "😖", + "emoticon": ["x(", "X("] + }, + { + "group": 0, + "hexcode": "1F623", + "label": "persevering face", + "order": 102, + "tags": [ + "concentrate", + "concentration", + "face", + "focus", + "headache", + "persevere", + "persevering" + ], + "unicode": "😣" + }, + { + "group": 0, + "hexcode": "1F61E", + "label": "disappointed face", + "order": 103, + "tags": [ + "awful", + "blame", + "dejected", + "disappointed", + "face", + "fail", + "losing", + "sad", + "unhappy" + ], + "unicode": "😞" + }, + { + "group": 0, + "hexcode": "1F613", + "label": "downcast face with sweat", + "order": 104, + "tags": [ + "close", + "cold", + "downcast", + "face", + "feels", + "headache", + "nervous", + "sad", + "scared", + "sweat", + "yikes" + ], + "unicode": "😓", + "emoticon": ":<" + }, + { + "group": 0, + "hexcode": "1F629", + "label": "weary face", + "order": 105, + "tags": [ + "crying", + "face", + "fail", + "feels", + "hungry", + "mad", + "nooo", + "sad", + "sleepy", + "tired", + "unhappy", + "weary" + ], + "unicode": "😩", + "emoticon": "D:" + }, + { + "group": 0, + "hexcode": "1F62B", + "label": "tired face", + "order": 106, + "tags": ["cost", "face", "feels", "nap", "sad", "sneeze", "tired"], + "unicode": "😫", + "emoticon": [":c", ":C"] + }, + { + "group": 0, + "hexcode": "1F971", + "label": "yawning face", + "order": 107, + "tags": [ + "bedtime", + "bored", + "face", + "goodnight", + "nap", + "night", + "sleep", + "sleepy", + "tired", + "whatever", + "yawn", + "yawning", + "zzz" + ], + "unicode": "🥱" + }, + { + "group": 0, + "hexcode": "1F624", + "label": "face with steam from nose", + "order": 108, + "tags": [ + "anger", + "angry", + "face", + "feels", + "fume", + "fuming", + "furious", + "fury", + "mad", + "nose", + "steam", + "triumph", + "unhappy", + "won" + ], + "unicode": "😤" + }, + { + "group": 0, + "hexcode": "1F621", + "label": "enraged face", + "order": 109, + "tags": [ + "anger", + "angry", + "enraged", + "face", + "feels", + "mad", + "maddening", + "pouting", + "rage", + "red", + "shade", + "unhappy", + "upset" + ], + "unicode": "😡", + "emoticon": ">:/" + }, + { + "group": 0, + "hexcode": "1F620", + "label": "angry face", + "order": 110, + "tags": [ + "anger", + "angry", + "blame", + "face", + "feels", + "frustrated", + "mad", + "maddening", + "rage", + "shade", + "unhappy", + "upset" + ], + "unicode": "😠" + }, + { + "group": 0, + "hexcode": "1F92C", + "label": "face with symbols on mouth", + "order": 111, + "tags": [ + "censor", + "cursing", + "cussing", + "face", + "mad", + "mouth", + "pissed", + "swearing", + "symbols" + ], + "unicode": "🤬", + "emoticon": ":@" + }, + { + "group": 0, + "hexcode": "1F608", + "label": "smiling face with horns", + "order": 112, + "tags": [ + "demon", + "devil", + "evil", + "face", + "fairy", + "fairytale", + "fantasy", + "horns", + "purple", + "shade", + "smile", + "smiling", + "tale" + ], + "unicode": "😈", + "emoticon": ">:)" + }, + { + "group": 0, + "hexcode": "1F47F", + "label": "angry face with horns", + "order": 113, + "tags": [ + "angry", + "demon", + "devil", + "evil", + "face", + "fairy", + "fairytale", + "fantasy", + "horns", + "imp", + "mischievous", + "purple", + "shade", + "tale" + ], + "unicode": "👿", + "emoticon": ">:(" + }, + { + "group": 0, + "hexcode": "1F480", + "label": "skull", + "order": 114, + "tags": [ + "body", + "dead", + "death", + "face", + "fairy", + "fairytale", + "i’m", + "lmao", + "monster", + "tale", + "yolo" + ], + "unicode": "💀" + }, + { + "group": 0, + "hexcode": "2620", + "label": "skull and crossbones", + "order": 116, + "tags": [ + "bone", + "crossbones", + "dead", + "death", + "face", + "monster", + "skull" + ], + "unicode": "☠️" + }, + { + "group": 0, + "hexcode": "1F4A9", + "label": "pile of poo", + "order": 117, + "tags": [ + "bs", + "comic", + "doo", + "dung", + "face", + "fml", + "monster", + "pile", + "poo", + "poop", + "smelly", + "smh", + "stink", + "stinks", + "stinky", + "turd" + ], + "unicode": "💩" + }, + { + "group": 0, + "hexcode": "1F921", + "label": "clown face", + "order": 118, + "tags": ["clown", "face"], + "unicode": "🤡" + }, + { + "group": 0, + "hexcode": "1F479", + "label": "ogre", + "order": 119, + "tags": [ + "creature", + "devil", + "face", + "fairy", + "fairytale", + "fantasy", + "mask", + "monster", + "scary", + "tale" + ], + "unicode": "👹", + "emoticon": ">0)" + }, + { + "group": 0, + "hexcode": "1F47A", + "label": "goblin", + "order": 120, + "tags": [ + "angry", + "creature", + "face", + "fairy", + "fairytale", + "fantasy", + "mask", + "mean", + "monster", + "tale" + ], + "unicode": "👺" + }, + { + "group": 0, + "hexcode": "1F47B", + "label": "ghost", + "order": 121, + "tags": [ + "boo", + "creature", + "excited", + "face", + "fairy", + "fairytale", + "fantasy", + "halloween", + "haunting", + "monster", + "scary", + "silly", + "tale" + ], + "unicode": "👻" + }, + { + "group": 0, + "hexcode": "1F47D", + "label": "alien", + "order": 122, + "tags": [ + "creature", + "extraterrestrial", + "face", + "fairy", + "fairytale", + "fantasy", + "monster", + "space", + "tale", + "ufo" + ], + "unicode": "👽️" + }, + { + "group": 0, + "hexcode": "1F47E", + "label": "alien monster", + "order": 123, + "tags": [ + "alien", + "creature", + "extraterrestrial", + "face", + "fairy", + "fairytale", + "fantasy", + "game", + "gamer", + "games", + "monster", + "pixelated", + "space", + "tale", + "ufo" + ], + "unicode": "👾" + }, + { + "group": 0, + "hexcode": "1F916", + "label": "robot", + "order": 124, + "tags": ["face", "monster"], + "unicode": "🤖" + }, + { + "group": 0, + "hexcode": "1F63A", + "label": "grinning cat", + "order": 125, + "tags": [ + "animal", + "cat", + "face", + "grinning", + "mouth", + "open", + "smile", + "smiling" + ], + "unicode": "😺" + }, + { + "group": 0, + "hexcode": "1F638", + "label": "grinning cat with smiling eyes", + "order": 126, + "tags": [ + "animal", + "cat", + "eye", + "eyes", + "face", + "grin", + "grinning", + "smile", + "smiling" + ], + "unicode": "😸" + }, + { + "group": 0, + "hexcode": "1F639", + "label": "cat with tears of joy", + "order": 127, + "tags": [ + "animal", + "cat", + "face", + "joy", + "laugh", + "laughing", + "lol", + "tear", + "tears" + ], + "unicode": "😹" + }, + { + "group": 0, + "hexcode": "1F63B", + "label": "smiling cat with heart-eyes", + "order": 128, + "tags": [ + "animal", + "cat", + "eye", + "face", + "heart", + "heart-eyes", + "love", + "smile", + "smiling" + ], + "unicode": "😻" + }, + { + "group": 0, + "hexcode": "1F63C", + "label": "cat with wry smile", + "order": 129, + "tags": ["animal", "cat", "face", "ironic", "smile", "wry"], + "unicode": "😼" + }, + { + "group": 0, + "hexcode": "1F63D", + "label": "kissing cat", + "order": 130, + "tags": [ + "animal", + "cat", + "closed", + "eye", + "eyes", + "face", + "kiss", + "kissing" + ], + "unicode": "😽", + "emoticon": ":3" + }, + { + "group": 0, + "hexcode": "1F640", + "label": "weary cat", + "order": 131, + "tags": ["animal", "cat", "face", "oh", "surprised", "weary"], + "unicode": "🙀" + }, + { + "group": 0, + "hexcode": "1F63F", + "label": "crying cat", + "order": 132, + "tags": ["animal", "cat", "cry", "crying", "face", "sad", "tear"], + "unicode": "😿" + }, + { + "group": 0, + "hexcode": "1F63E", + "label": "pouting cat", + "order": 133, + "tags": ["animal", "cat", "face", "pouting"], + "unicode": "😾" + }, + { + "group": 0, + "hexcode": "1F648", + "label": "see-no-evil monkey", + "order": 134, + "tags": [ + "embarrassed", + "evil", + "face", + "forbidden", + "forgot", + "gesture", + "hide", + "monkey", + "no", + "omg", + "prohibited", + "scared", + "secret", + "smh", + "watch" + ], + "unicode": "🙈" + }, + { + "group": 0, + "hexcode": "1F649", + "label": "hear-no-evil monkey", + "order": 135, + "tags": [ + "animal", + "ears", + "evil", + "face", + "forbidden", + "gesture", + "hear", + "listen", + "monkey", + "no", + "not", + "prohibited", + "secret", + "shh", + "tmi" + ], + "unicode": "🙉" + }, + { + "group": 0, + "hexcode": "1F64A", + "label": "speak-no-evil monkey", + "order": 136, + "tags": [ + "animal", + "evil", + "face", + "forbidden", + "gesture", + "monkey", + "no", + "not", + "oops", + "prohibited", + "quiet", + "secret", + "speak", + "stealth" + ], + "unicode": "🙊" + }, + { + "group": 0, + "hexcode": "1F48C", + "label": "love letter", + "order": 137, + "tags": ["heart", "letter", "love", "mail", "romance", "valentine"], + "unicode": "💌" + }, + { + "group": 0, + "hexcode": "1F498", + "label": "heart with arrow", + "order": 138, + "tags": [ + "143", + "adorbs", + "arrow", + "cupid", + "date", + "emotion", + "heart", + "ily", + "love", + "romance", + "valentine" + ], + "unicode": "💘" + }, + { + "group": 0, + "hexcode": "1F49D", + "label": "heart with ribbon", + "order": 139, + "tags": [ + "143", + "anniversary", + "emotion", + "heart", + "ily", + "kisses", + "ribbon", + "valentine", + "xoxo" + ], + "unicode": "💝" + }, + { + "group": 0, + "hexcode": "1F496", + "label": "sparkling heart", + "order": 140, + "tags": [ + "143", + "emotion", + "excited", + "good", + "heart", + "ily", + "kisses", + "morning", + "night", + "sparkle", + "sparkling", + "xoxo" + ], + "unicode": "💖" + }, + { + "group": 0, + "hexcode": "1F497", + "label": "growing heart", + "order": 141, + "tags": [ + "143", + "emotion", + "excited", + "growing", + "heart", + "heartpulse", + "ily", + "kisses", + "muah", + "nervous", + "pulse", + "xoxo" + ], + "unicode": "💗" + }, + { + "group": 0, + "hexcode": "1F493", + "label": "beating heart", + "order": 142, + "tags": [ + "143", + "beating", + "cardio", + "emotion", + "heart", + "heartbeat", + "ily", + "love", + "pulsating", + "pulse" + ], + "unicode": "💓" + }, + { + "group": 0, + "hexcode": "1F49E", + "label": "revolving hearts", + "order": 143, + "tags": [ + "143", + "adorbs", + "anniversary", + "emotion", + "heart", + "hearts", + "revolving" + ], + "unicode": "💞" + }, + { + "group": 0, + "hexcode": "1F495", + "label": "two hearts", + "order": 144, + "tags": [ + "143", + "anniversary", + "date", + "dating", + "emotion", + "heart", + "hearts", + "ily", + "kisses", + "love", + "loving", + "two", + "xoxo" + ], + "unicode": "💕" + }, + { + "group": 0, + "hexcode": "1F49F", + "label": "heart decoration", + "order": 145, + "tags": [ + "143", + "decoration", + "emotion", + "heart", + "hearth", + "purple", + "white" + ], + "unicode": "💟" + }, + { + "group": 0, + "hexcode": "2763", + "label": "heart exclamation", + "order": 147, + "tags": ["exclamation", "heart", "heavy", "mark", "punctuation"], + "unicode": "❣️" + }, + { + "group": 0, + "hexcode": "1F494", + "label": "broken heart", + "order": 148, + "tags": [ + "break", + "broken", + "crushed", + "emotion", + "heart", + "heartbroken", + "lonely", + "sad" + ], + "unicode": "💔", + "emoticon": "", + "skins": [ + { + "group": 1, + "hexcode": "1F9D9-1F3FB-200D-2642-FE0F", + "label": "man mage: light skin tone", + "order": 1736, + "unicode": "🧙🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D9-1F3FC-200D-2642-FE0F", + "label": "man mage: medium-light skin tone", + "order": 1738, + "unicode": "🧙🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D9-1F3FD-200D-2642-FE0F", + "label": "man mage: medium skin tone", + "order": 1740, + "unicode": "🧙🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D9-1F3FE-200D-2642-FE0F", + "label": "man mage: medium-dark skin tone", + "order": 1742, + "unicode": "🧙🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D9-1F3FF-200D-2642-FE0F", + "label": "man mage: dark skin tone", + "order": 1744, + "unicode": "🧙🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D9-200D-2640-FE0F", + "label": "woman mage", + "order": 1746, + "tags": [ + "fantasy", + "mage", + "magic", + "play", + "sorcerer", + "sorceress", + "sorcery", + "spell", + "summon", + "witch", + "wizard", + "woman" + ], + "unicode": "🧙‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D9-1F3FB-200D-2640-FE0F", + "label": "woman mage: light skin tone", + "order": 1748, + "unicode": "🧙🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D9-1F3FC-200D-2640-FE0F", + "label": "woman mage: medium-light skin tone", + "order": 1750, + "unicode": "🧙🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D9-1F3FD-200D-2640-FE0F", + "label": "woman mage: medium skin tone", + "order": 1752, + "unicode": "🧙🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D9-1F3FE-200D-2640-FE0F", + "label": "woman mage: medium-dark skin tone", + "order": 1754, + "unicode": "🧙🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D9-1F3FF-200D-2640-FE0F", + "label": "woman mage: dark skin tone", + "order": 1756, + "unicode": "🧙🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DA", + "label": "fairy", + "order": 1758, + "tags": [ + "fairytale", + "fantasy", + "myth", + "person", + "pixie", + "tale", + "wings" + ], + "unicode": "🧚", + "skins": [ + { + "group": 1, + "hexcode": "1F9DA-1F3FB", + "label": "fairy: light skin tone", + "order": 1759, + "unicode": "🧚🏻" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FC", + "label": "fairy: medium-light skin tone", + "order": 1760, + "unicode": "🧚🏼" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FD", + "label": "fairy: medium skin tone", + "order": 1761, + "unicode": "🧚🏽" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FE", + "label": "fairy: medium-dark skin tone", + "order": 1762, + "unicode": "🧚🏾" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FF", + "label": "fairy: dark skin tone", + "order": 1763, + "unicode": "🧚🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DA-200D-2642-FE0F", + "label": "man fairy", + "order": 1764, + "tags": [ + "fairy", + "fairytale", + "fantasy", + "man", + "myth", + "oberon", + "person", + "pixie", + "puck", + "tale", + "wings" + ], + "unicode": "🧚‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9DA-1F3FB-200D-2642-FE0F", + "label": "man fairy: light skin tone", + "order": 1766, + "unicode": "🧚🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FC-200D-2642-FE0F", + "label": "man fairy: medium-light skin tone", + "order": 1768, + "unicode": "🧚🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FD-200D-2642-FE0F", + "label": "man fairy: medium skin tone", + "order": 1770, + "unicode": "🧚🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FE-200D-2642-FE0F", + "label": "man fairy: medium-dark skin tone", + "order": 1772, + "unicode": "🧚🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FF-200D-2642-FE0F", + "label": "man fairy: dark skin tone", + "order": 1774, + "unicode": "🧚🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DA-200D-2640-FE0F", + "label": "woman fairy", + "order": 1776, + "tags": [ + "fairy", + "fairytale", + "fantasy", + "myth", + "person", + "pixie", + "tale", + "titania", + "wings", + "woman" + ], + "unicode": "🧚‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9DA-1F3FB-200D-2640-FE0F", + "label": "woman fairy: light skin tone", + "order": 1778, + "unicode": "🧚🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FC-200D-2640-FE0F", + "label": "woman fairy: medium-light skin tone", + "order": 1780, + "unicode": "🧚🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FD-200D-2640-FE0F", + "label": "woman fairy: medium skin tone", + "order": 1782, + "unicode": "🧚🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FE-200D-2640-FE0F", + "label": "woman fairy: medium-dark skin tone", + "order": 1784, + "unicode": "🧚🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DA-1F3FF-200D-2640-FE0F", + "label": "woman fairy: dark skin tone", + "order": 1786, + "unicode": "🧚🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DB", + "label": "vampire", + "order": 1788, + "tags": [ + "blood", + "dracula", + "fangs", + "halloween", + "scary", + "supernatural", + "teeth", + "undead" + ], + "unicode": "🧛", + "emoticon": ":E", + "skins": [ + { + "group": 1, + "hexcode": "1F9DB-1F3FB", + "label": "vampire: light skin tone", + "order": 1789, + "unicode": "🧛🏻" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FC", + "label": "vampire: medium-light skin tone", + "order": 1790, + "unicode": "🧛🏼" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FD", + "label": "vampire: medium skin tone", + "order": 1791, + "unicode": "🧛🏽" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FE", + "label": "vampire: medium-dark skin tone", + "order": 1792, + "unicode": "🧛🏾" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FF", + "label": "vampire: dark skin tone", + "order": 1793, + "unicode": "🧛🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DB-200D-2642-FE0F", + "label": "man vampire", + "order": 1794, + "tags": [ + "blood", + "fangs", + "halloween", + "man", + "scary", + "supernatural", + "teeth", + "undead", + "vampire" + ], + "unicode": "🧛‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9DB-1F3FB-200D-2642-FE0F", + "label": "man vampire: light skin tone", + "order": 1796, + "unicode": "🧛🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FC-200D-2642-FE0F", + "label": "man vampire: medium-light skin tone", + "order": 1798, + "unicode": "🧛🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FD-200D-2642-FE0F", + "label": "man vampire: medium skin tone", + "order": 1800, + "unicode": "🧛🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FE-200D-2642-FE0F", + "label": "man vampire: medium-dark skin tone", + "order": 1802, + "unicode": "🧛🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FF-200D-2642-FE0F", + "label": "man vampire: dark skin tone", + "order": 1804, + "unicode": "🧛🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DB-200D-2640-FE0F", + "label": "woman vampire", + "order": 1806, + "tags": [ + "blood", + "fangs", + "halloween", + "scary", + "supernatural", + "teeth", + "undead", + "vampire", + "woman" + ], + "unicode": "🧛‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9DB-1F3FB-200D-2640-FE0F", + "label": "woman vampire: light skin tone", + "order": 1808, + "unicode": "🧛🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FC-200D-2640-FE0F", + "label": "woman vampire: medium-light skin tone", + "order": 1810, + "unicode": "🧛🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FD-200D-2640-FE0F", + "label": "woman vampire: medium skin tone", + "order": 1812, + "unicode": "🧛🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FE-200D-2640-FE0F", + "label": "woman vampire: medium-dark skin tone", + "order": 1814, + "unicode": "🧛🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DB-1F3FF-200D-2640-FE0F", + "label": "woman vampire: dark skin tone", + "order": 1816, + "unicode": "🧛🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DC", + "label": "merperson", + "order": 1818, + "tags": [ + "creature", + "fairytale", + "folklore", + "ocean", + "sea", + "siren", + "trident" + ], + "unicode": "🧜", + "skins": [ + { + "group": 1, + "hexcode": "1F9DC-1F3FB", + "label": "merperson: light skin tone", + "order": 1819, + "unicode": "🧜🏻" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FC", + "label": "merperson: medium-light skin tone", + "order": 1820, + "unicode": "🧜🏼" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FD", + "label": "merperson: medium skin tone", + "order": 1821, + "unicode": "🧜🏽" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FE", + "label": "merperson: medium-dark skin tone", + "order": 1822, + "unicode": "🧜🏾" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FF", + "label": "merperson: dark skin tone", + "order": 1823, + "unicode": "🧜🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DC-200D-2642-FE0F", + "label": "merman", + "order": 1824, + "tags": [ + "creature", + "fairytale", + "folklore", + "neptune", + "ocean", + "poseidon", + "sea", + "siren", + "trident", + "triton" + ], + "unicode": "🧜‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9DC-1F3FB-200D-2642-FE0F", + "label": "merman: light skin tone", + "order": 1826, + "unicode": "🧜🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FC-200D-2642-FE0F", + "label": "merman: medium-light skin tone", + "order": 1828, + "unicode": "🧜🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FD-200D-2642-FE0F", + "label": "merman: medium skin tone", + "order": 1830, + "unicode": "🧜🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FE-200D-2642-FE0F", + "label": "merman: medium-dark skin tone", + "order": 1832, + "unicode": "🧜🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FF-200D-2642-FE0F", + "label": "merman: dark skin tone", + "order": 1834, + "unicode": "🧜🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DC-200D-2640-FE0F", + "label": "mermaid", + "order": 1836, + "tags": [ + "creature", + "fairytale", + "folklore", + "merwoman", + "ocean", + "sea", + "siren", + "trident" + ], + "unicode": "🧜‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9DC-1F3FB-200D-2640-FE0F", + "label": "mermaid: light skin tone", + "order": 1838, + "unicode": "🧜🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FC-200D-2640-FE0F", + "label": "mermaid: medium-light skin tone", + "order": 1840, + "unicode": "🧜🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FD-200D-2640-FE0F", + "label": "mermaid: medium skin tone", + "order": 1842, + "unicode": "🧜🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FE-200D-2640-FE0F", + "label": "mermaid: medium-dark skin tone", + "order": 1844, + "unicode": "🧜🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DC-1F3FF-200D-2640-FE0F", + "label": "mermaid: dark skin tone", + "order": 1846, + "unicode": "🧜🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DD", + "label": "elf", + "order": 1848, + "tags": [ + "elves", + "enchantment", + "fantasy", + "folklore", + "magic", + "magical", + "myth" + ], + "unicode": "🧝", + "skins": [ + { + "group": 1, + "hexcode": "1F9DD-1F3FB", + "label": "elf: light skin tone", + "order": 1849, + "unicode": "🧝🏻" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FC", + "label": "elf: medium-light skin tone", + "order": 1850, + "unicode": "🧝🏼" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FD", + "label": "elf: medium skin tone", + "order": 1851, + "unicode": "🧝🏽" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FE", + "label": "elf: medium-dark skin tone", + "order": 1852, + "unicode": "🧝🏾" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FF", + "label": "elf: dark skin tone", + "order": 1853, + "unicode": "🧝🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DD-200D-2642-FE0F", + "label": "man elf", + "order": 1854, + "tags": [ + "elf", + "elves", + "enchantment", + "fantasy", + "folklore", + "magic", + "magical", + "man", + "myth" + ], + "unicode": "🧝‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9DD-1F3FB-200D-2642-FE0F", + "label": "man elf: light skin tone", + "order": 1856, + "unicode": "🧝🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FC-200D-2642-FE0F", + "label": "man elf: medium-light skin tone", + "order": 1858, + "unicode": "🧝🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FD-200D-2642-FE0F", + "label": "man elf: medium skin tone", + "order": 1860, + "unicode": "🧝🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FE-200D-2642-FE0F", + "label": "man elf: medium-dark skin tone", + "order": 1862, + "unicode": "🧝🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FF-200D-2642-FE0F", + "label": "man elf: dark skin tone", + "order": 1864, + "unicode": "🧝🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DD-200D-2640-FE0F", + "label": "woman elf", + "order": 1866, + "tags": [ + "elf", + "elves", + "enchantment", + "fantasy", + "folklore", + "magic", + "magical", + "myth", + "woman" + ], + "unicode": "🧝‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9DD-1F3FB-200D-2640-FE0F", + "label": "woman elf: light skin tone", + "order": 1868, + "unicode": "🧝🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FC-200D-2640-FE0F", + "label": "woman elf: medium-light skin tone", + "order": 1870, + "unicode": "🧝🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FD-200D-2640-FE0F", + "label": "woman elf: medium skin tone", + "order": 1872, + "unicode": "🧝🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FE-200D-2640-FE0F", + "label": "woman elf: medium-dark skin tone", + "order": 1874, + "unicode": "🧝🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DD-1F3FF-200D-2640-FE0F", + "label": "woman elf: dark skin tone", + "order": 1876, + "unicode": "🧝🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9DE", + "label": "genie", + "order": 1878, + "tags": ["djinn", "fantasy", "jinn", "lamp", "myth", "rub", "wishes"], + "unicode": "🧞" + }, + { + "group": 1, + "hexcode": "1F9DE-200D-2642-FE0F", + "label": "man genie", + "order": 1879, + "tags": [ + "djinn", + "fantasy", + "genie", + "jinn", + "lamp", + "man", + "myth", + "rub", + "wishes" + ], + "unicode": "🧞‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DE-200D-2640-FE0F", + "label": "woman genie", + "order": 1881, + "tags": [ + "djinn", + "fantasy", + "genie", + "jinn", + "lamp", + "myth", + "rub", + "wishes", + "woman" + ], + "unicode": "🧞‍♀️" + }, + { + "group": 1, + "hexcode": "1F9DF", + "label": "zombie", + "order": 1883, + "tags": [ + "apocalypse", + "dead", + "halloween", + "horror", + "scary", + "undead", + "walking" + ], + "unicode": "🧟", + "emoticon": "8#" + }, + { + "group": 1, + "hexcode": "1F9DF-200D-2642-FE0F", + "label": "man zombie", + "order": 1884, + "tags": [ + "apocalypse", + "dead", + "halloween", + "horror", + "man", + "scary", + "undead", + "walking", + "zombie" + ], + "unicode": "🧟‍♂️" + }, + { + "group": 1, + "hexcode": "1F9DF-200D-2640-FE0F", + "label": "woman zombie", + "order": 1886, + "tags": [ + "apocalypse", + "dead", + "halloween", + "horror", + "scary", + "undead", + "walking", + "woman", + "zombie" + ], + "unicode": "🧟‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CC", + "label": "troll", + "order": 1888, + "tags": ["fairy", "fantasy", "monster", "tale", "trolling"], + "unicode": "🧌" + }, + { + "group": 1, + "hexcode": "1F486", + "label": "person getting massage", + "order": 1889, + "tags": [ + "face", + "getting", + "headache", + "massage", + "person", + "relax", + "relaxing", + "salon", + "soothe", + "spa", + "tension", + "therapy", + "treatment" + ], + "unicode": "💆", + "skins": [ + { + "group": 1, + "hexcode": "1F486-1F3FB", + "label": "person getting massage: light skin tone", + "order": 1890, + "unicode": "💆🏻" + }, + { + "group": 1, + "hexcode": "1F486-1F3FC", + "label": "person getting massage: medium-light skin tone", + "order": 1891, + "unicode": "💆🏼" + }, + { + "group": 1, + "hexcode": "1F486-1F3FD", + "label": "person getting massage: medium skin tone", + "order": 1892, + "unicode": "💆🏽" + }, + { + "group": 1, + "hexcode": "1F486-1F3FE", + "label": "person getting massage: medium-dark skin tone", + "order": 1893, + "unicode": "💆🏾" + }, + { + "group": 1, + "hexcode": "1F486-1F3FF", + "label": "person getting massage: dark skin tone", + "order": 1894, + "unicode": "💆🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F486-200D-2642-FE0F", + "label": "man getting massage", + "order": 1895, + "tags": [ + "face", + "getting", + "headache", + "man", + "massage", + "relax", + "relaxing", + "salon", + "soothe", + "spa", + "tension", + "therapy", + "treatment" + ], + "unicode": "💆‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F486-1F3FB-200D-2642-FE0F", + "label": "man getting massage: light skin tone", + "order": 1897, + "unicode": "💆🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F486-1F3FC-200D-2642-FE0F", + "label": "man getting massage: medium-light skin tone", + "order": 1899, + "unicode": "💆🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F486-1F3FD-200D-2642-FE0F", + "label": "man getting massage: medium skin tone", + "order": 1901, + "unicode": "💆🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F486-1F3FE-200D-2642-FE0F", + "label": "man getting massage: medium-dark skin tone", + "order": 1903, + "unicode": "💆🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F486-1F3FF-200D-2642-FE0F", + "label": "man getting massage: dark skin tone", + "order": 1905, + "unicode": "💆🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F486-200D-2640-FE0F", + "label": "woman getting massage", + "order": 1907, + "tags": [ + "face", + "getting", + "headache", + "massage", + "relax", + "relaxing", + "salon", + "soothe", + "spa", + "tension", + "therapy", + "treatment", + "woman" + ], + "unicode": "💆‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F486-1F3FB-200D-2640-FE0F", + "label": "woman getting massage: light skin tone", + "order": 1909, + "unicode": "💆🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F486-1F3FC-200D-2640-FE0F", + "label": "woman getting massage: medium-light skin tone", + "order": 1911, + "unicode": "💆🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F486-1F3FD-200D-2640-FE0F", + "label": "woman getting massage: medium skin tone", + "order": 1913, + "unicode": "💆🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F486-1F3FE-200D-2640-FE0F", + "label": "woman getting massage: medium-dark skin tone", + "order": 1915, + "unicode": "💆🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F486-1F3FF-200D-2640-FE0F", + "label": "woman getting massage: dark skin tone", + "order": 1917, + "unicode": "💆🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F487", + "label": "person getting haircut", + "order": 1919, + "tags": [ + "barber", + "beauty", + "chop", + "cosmetology", + "cut", + "groom", + "hair", + "haircut", + "parlor", + "person", + "shears", + "style" + ], + "unicode": "💇", + "skins": [ + { + "group": 1, + "hexcode": "1F487-1F3FB", + "label": "person getting haircut: light skin tone", + "order": 1920, + "unicode": "💇🏻" + }, + { + "group": 1, + "hexcode": "1F487-1F3FC", + "label": "person getting haircut: medium-light skin tone", + "order": 1921, + "unicode": "💇🏼" + }, + { + "group": 1, + "hexcode": "1F487-1F3FD", + "label": "person getting haircut: medium skin tone", + "order": 1922, + "unicode": "💇🏽" + }, + { + "group": 1, + "hexcode": "1F487-1F3FE", + "label": "person getting haircut: medium-dark skin tone", + "order": 1923, + "unicode": "💇🏾" + }, + { + "group": 1, + "hexcode": "1F487-1F3FF", + "label": "person getting haircut: dark skin tone", + "order": 1924, + "unicode": "💇🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F487-200D-2642-FE0F", + "label": "man getting haircut", + "order": 1925, + "tags": [ + "barber", + "beauty", + "chop", + "cosmetology", + "cut", + "groom", + "hair", + "haircut", + "man", + "parlor", + "person", + "shears", + "style" + ], + "unicode": "💇‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F487-1F3FB-200D-2642-FE0F", + "label": "man getting haircut: light skin tone", + "order": 1927, + "unicode": "💇🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F487-1F3FC-200D-2642-FE0F", + "label": "man getting haircut: medium-light skin tone", + "order": 1929, + "unicode": "💇🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F487-1F3FD-200D-2642-FE0F", + "label": "man getting haircut: medium skin tone", + "order": 1931, + "unicode": "💇🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F487-1F3FE-200D-2642-FE0F", + "label": "man getting haircut: medium-dark skin tone", + "order": 1933, + "unicode": "💇🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F487-1F3FF-200D-2642-FE0F", + "label": "man getting haircut: dark skin tone", + "order": 1935, + "unicode": "💇🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F487-200D-2640-FE0F", + "label": "woman getting haircut", + "order": 1937, + "tags": [ + "barber", + "beauty", + "chop", + "cosmetology", + "cut", + "groom", + "hair", + "haircut", + "parlor", + "person", + "shears", + "style", + "woman" + ], + "unicode": "💇‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F487-1F3FB-200D-2640-FE0F", + "label": "woman getting haircut: light skin tone", + "order": 1939, + "unicode": "💇🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F487-1F3FC-200D-2640-FE0F", + "label": "woman getting haircut: medium-light skin tone", + "order": 1941, + "unicode": "💇🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F487-1F3FD-200D-2640-FE0F", + "label": "woman getting haircut: medium skin tone", + "order": 1943, + "unicode": "💇🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F487-1F3FE-200D-2640-FE0F", + "label": "woman getting haircut: medium-dark skin tone", + "order": 1945, + "unicode": "💇🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F487-1F3FF-200D-2640-FE0F", + "label": "woman getting haircut: dark skin tone", + "order": 1947, + "unicode": "💇🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B6", + "label": "person walking", + "order": 1949, + "tags": [ + "amble", + "gait", + "hike", + "man", + "pace", + "pedestrian", + "person", + "stride", + "stroll", + "walk", + "walking" + ], + "unicode": "🚶", + "skins": [ + { + "group": 1, + "hexcode": "1F6B6-1F3FB", + "label": "person walking: light skin tone", + "order": 1950, + "unicode": "🚶🏻" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FC", + "label": "person walking: medium-light skin tone", + "order": 1951, + "unicode": "🚶🏼" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FD", + "label": "person walking: medium skin tone", + "order": 1952, + "unicode": "🚶🏽" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FE", + "label": "person walking: medium-dark skin tone", + "order": 1953, + "unicode": "🚶🏾" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FF", + "label": "person walking: dark skin tone", + "order": 1954, + "unicode": "🚶🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B6-200D-2642-FE0F", + "label": "man walking", + "order": 1955, + "tags": [ + "amble", + "gait", + "hike", + "man", + "pace", + "pedestrian", + "stride", + "stroll", + "walk", + "walking" + ], + "unicode": "🚶‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B6-1F3FB-200D-2642-FE0F", + "label": "man walking: light skin tone", + "order": 1957, + "unicode": "🚶🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FC-200D-2642-FE0F", + "label": "man walking: medium-light skin tone", + "order": 1959, + "unicode": "🚶🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FD-200D-2642-FE0F", + "label": "man walking: medium skin tone", + "order": 1961, + "unicode": "🚶🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FE-200D-2642-FE0F", + "label": "man walking: medium-dark skin tone", + "order": 1963, + "unicode": "🚶🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FF-200D-2642-FE0F", + "label": "man walking: dark skin tone", + "order": 1965, + "unicode": "🚶🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B6-200D-2640-FE0F", + "label": "woman walking", + "order": 1967, + "tags": [ + "amble", + "gait", + "hike", + "man", + "pace", + "pedestrian", + "stride", + "stroll", + "walk", + "walking", + "woman" + ], + "unicode": "🚶‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B6-1F3FB-200D-2640-FE0F", + "label": "woman walking: light skin tone", + "order": 1969, + "unicode": "🚶🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FC-200D-2640-FE0F", + "label": "woman walking: medium-light skin tone", + "order": 1971, + "unicode": "🚶🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FD-200D-2640-FE0F", + "label": "woman walking: medium skin tone", + "order": 1973, + "unicode": "🚶🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FE-200D-2640-FE0F", + "label": "woman walking: medium-dark skin tone", + "order": 1975, + "unicode": "🚶🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FF-200D-2640-FE0F", + "label": "woman walking: dark skin tone", + "order": 1977, + "unicode": "🚶🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B6-200D-27A1-FE0F", + "label": "person walking facing right", + "order": 1979, + "tags": [ + "amble", + "gait", + "hike", + "man", + "pace", + "pedestrian", + "person", + "stride", + "stroll", + "walk", + "walking" + ], + "unicode": "🚶‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B6-1F3FB-200D-27A1-FE0F", + "label": "person walking facing right", + "order": 1981, + "unicode": "🚶🏻‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FC-200D-27A1-FE0F", + "label": "person walking facing right", + "order": 1983, + "unicode": "🚶🏼‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FD-200D-27A1-FE0F", + "label": "person walking facing right", + "order": 1985, + "unicode": "🚶🏽‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FE-200D-27A1-FE0F", + "label": "person walking facing right", + "order": 1987, + "unicode": "🚶🏾‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FF-200D-27A1-FE0F", + "label": "person walking facing right", + "order": 1989, + "unicode": "🚶🏿‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B6-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman walking facing right", + "order": 1991, + "tags": [ + "amble", + "gait", + "hike", + "man", + "pace", + "pedestrian", + "stride", + "stroll", + "walk", + "walking", + "woman" + ], + "unicode": "🚶‍♀️‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B6-1F3FB-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman walking facing right", + "order": 1995, + "unicode": "🚶🏻‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FC-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman walking facing right", + "order": 1999, + "unicode": "🚶🏼‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FD-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman walking facing right", + "order": 2003, + "unicode": "🚶🏽‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FE-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman walking facing right", + "order": 2007, + "unicode": "🚶🏾‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FF-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman walking facing right", + "order": 2011, + "unicode": "🚶🏿‍♀️‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B6-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man walking facing right", + "order": 2015, + "tags": [ + "amble", + "gait", + "hike", + "man", + "pace", + "pedestrian", + "stride", + "stroll", + "walk", + "walking" + ], + "unicode": "🚶‍♂️‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B6-1F3FB-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man walking facing right", + "order": 2019, + "unicode": "🚶🏻‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FC-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man walking facing right", + "order": 2023, + "unicode": "🚶🏼‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FD-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man walking facing right", + "order": 2027, + "unicode": "🚶🏽‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FE-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man walking facing right", + "order": 2031, + "unicode": "🚶🏾‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F6B6-1F3FF-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man walking facing right", + "order": 2035, + "unicode": "🚶🏿‍♂️‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CD", + "label": "person standing", + "order": 2039, + "tags": ["person", "stand", "standing"], + "unicode": "🧍", + "skins": [ + { + "group": 1, + "hexcode": "1F9CD-1F3FB", + "label": "person standing: light skin tone", + "order": 2040, + "unicode": "🧍🏻" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FC", + "label": "person standing: medium-light skin tone", + "order": 2041, + "unicode": "🧍🏼" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FD", + "label": "person standing: medium skin tone", + "order": 2042, + "unicode": "🧍🏽" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FE", + "label": "person standing: medium-dark skin tone", + "order": 2043, + "unicode": "🧍🏾" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FF", + "label": "person standing: dark skin tone", + "order": 2044, + "unicode": "🧍🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CD-200D-2642-FE0F", + "label": "man standing", + "order": 2045, + "tags": ["man", "stand", "standing"], + "unicode": "🧍‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9CD-1F3FB-200D-2642-FE0F", + "label": "man standing: light skin tone", + "order": 2047, + "unicode": "🧍🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FC-200D-2642-FE0F", + "label": "man standing: medium-light skin tone", + "order": 2049, + "unicode": "🧍🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FD-200D-2642-FE0F", + "label": "man standing: medium skin tone", + "order": 2051, + "unicode": "🧍🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FE-200D-2642-FE0F", + "label": "man standing: medium-dark skin tone", + "order": 2053, + "unicode": "🧍🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FF-200D-2642-FE0F", + "label": "man standing: dark skin tone", + "order": 2055, + "unicode": "🧍🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CD-200D-2640-FE0F", + "label": "woman standing", + "order": 2057, + "tags": ["stand", "standing", "woman"], + "unicode": "🧍‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9CD-1F3FB-200D-2640-FE0F", + "label": "woman standing: light skin tone", + "order": 2059, + "unicode": "🧍🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FC-200D-2640-FE0F", + "label": "woman standing: medium-light skin tone", + "order": 2061, + "unicode": "🧍🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FD-200D-2640-FE0F", + "label": "woman standing: medium skin tone", + "order": 2063, + "unicode": "🧍🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FE-200D-2640-FE0F", + "label": "woman standing: medium-dark skin tone", + "order": 2065, + "unicode": "🧍🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CD-1F3FF-200D-2640-FE0F", + "label": "woman standing: dark skin tone", + "order": 2067, + "unicode": "🧍🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CE", + "label": "person kneeling", + "order": 2069, + "tags": ["kneel", "kneeling", "knees", "person"], + "unicode": "🧎", + "skins": [ + { + "group": 1, + "hexcode": "1F9CE-1F3FB", + "label": "person kneeling: light skin tone", + "order": 2070, + "unicode": "🧎🏻" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FC", + "label": "person kneeling: medium-light skin tone", + "order": 2071, + "unicode": "🧎🏼" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FD", + "label": "person kneeling: medium skin tone", + "order": 2072, + "unicode": "🧎🏽" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FE", + "label": "person kneeling: medium-dark skin tone", + "order": 2073, + "unicode": "🧎🏾" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FF", + "label": "person kneeling: dark skin tone", + "order": 2074, + "unicode": "🧎🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CE-200D-2642-FE0F", + "label": "man kneeling", + "order": 2075, + "tags": ["kneel", "kneeling", "knees", "man"], + "unicode": "🧎‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9CE-1F3FB-200D-2642-FE0F", + "label": "man kneeling: light skin tone", + "order": 2077, + "unicode": "🧎🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FC-200D-2642-FE0F", + "label": "man kneeling: medium-light skin tone", + "order": 2079, + "unicode": "🧎🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FD-200D-2642-FE0F", + "label": "man kneeling: medium skin tone", + "order": 2081, + "unicode": "🧎🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FE-200D-2642-FE0F", + "label": "man kneeling: medium-dark skin tone", + "order": 2083, + "unicode": "🧎🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FF-200D-2642-FE0F", + "label": "man kneeling: dark skin tone", + "order": 2085, + "unicode": "🧎🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CE-200D-2640-FE0F", + "label": "woman kneeling", + "order": 2087, + "tags": ["kneel", "kneeling", "knees", "woman"], + "unicode": "🧎‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9CE-1F3FB-200D-2640-FE0F", + "label": "woman kneeling: light skin tone", + "order": 2089, + "unicode": "🧎🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FC-200D-2640-FE0F", + "label": "woman kneeling: medium-light skin tone", + "order": 2091, + "unicode": "🧎🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FD-200D-2640-FE0F", + "label": "woman kneeling: medium skin tone", + "order": 2093, + "unicode": "🧎🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FE-200D-2640-FE0F", + "label": "woman kneeling: medium-dark skin tone", + "order": 2095, + "unicode": "🧎🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FF-200D-2640-FE0F", + "label": "woman kneeling: dark skin tone", + "order": 2097, + "unicode": "🧎🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CE-200D-27A1-FE0F", + "label": "person kneeling facing right", + "order": 2099, + "tags": ["kneel", "kneeling", "knees", "person"], + "unicode": "🧎‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F9CE-1F3FB-200D-27A1-FE0F", + "label": "person kneeling facing right", + "order": 2101, + "unicode": "🧎🏻‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FC-200D-27A1-FE0F", + "label": "person kneeling facing right", + "order": 2103, + "unicode": "🧎🏼‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FD-200D-27A1-FE0F", + "label": "person kneeling facing right", + "order": 2105, + "unicode": "🧎🏽‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FE-200D-27A1-FE0F", + "label": "person kneeling facing right", + "order": 2107, + "unicode": "🧎🏾‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FF-200D-27A1-FE0F", + "label": "person kneeling facing right", + "order": 2109, + "unicode": "🧎🏿‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CE-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman kneeling facing right", + "order": 2111, + "tags": ["kneel", "kneeling", "knees", "woman"], + "unicode": "🧎‍♀️‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F9CE-1F3FB-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman kneeling facing right", + "order": 2115, + "unicode": "🧎🏻‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FC-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman kneeling facing right", + "order": 2119, + "unicode": "🧎🏼‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FD-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman kneeling facing right", + "order": 2123, + "unicode": "🧎🏽‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FE-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman kneeling facing right", + "order": 2127, + "unicode": "🧎🏾‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FF-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman kneeling facing right", + "order": 2131, + "unicode": "🧎🏿‍♀️‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9CE-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man kneeling facing right", + "order": 2135, + "tags": ["kneel", "kneeling", "knees", "man"], + "unicode": "🧎‍♂️‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F9CE-1F3FB-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man kneeling facing right", + "order": 2139, + "unicode": "🧎🏻‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FC-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man kneeling facing right", + "order": 2143, + "unicode": "🧎🏼‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FD-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man kneeling facing right", + "order": 2147, + "unicode": "🧎🏽‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FE-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man kneeling facing right", + "order": 2151, + "unicode": "🧎🏾‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F9CE-1F3FF-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man kneeling facing right", + "order": 2155, + "unicode": "🧎🏿‍♂️‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9AF", + "label": "person with white cane", + "order": 2159, + "tags": [ + "accessibility", + "blind", + "cane", + "person", + "probing", + "white" + ], + "unicode": "🧑‍🦯", + "skins": [ + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F9AF", + "label": "person with white cane: light skin tone", + "order": 2160, + "unicode": "🧑🏻‍🦯" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F9AF", + "label": "person with white cane: medium-light skin tone", + "order": 2161, + "unicode": "🧑🏼‍🦯" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F9AF", + "label": "person with white cane: medium skin tone", + "order": 2162, + "unicode": "🧑🏽‍🦯" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F9AF", + "label": "person with white cane: medium-dark skin tone", + "order": 2163, + "unicode": "🧑🏾‍🦯" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F9AF", + "label": "person with white cane: dark skin tone", + "order": 2164, + "unicode": "🧑🏿‍🦯" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9AF-200D-27A1-FE0F", + "label": "person with white cane facing right", + "order": 2165, + "tags": [ + "accessibility", + "blind", + "cane", + "person", + "probing", + "white" + ], + "unicode": "🧑‍🦯‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F9AF-200D-27A1-FE0F", + "label": "person with white cane facing right", + "order": 2167, + "unicode": "🧑🏻‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F9AF-200D-27A1-FE0F", + "label": "person with white cane facing right", + "order": 2169, + "unicode": "🧑🏼‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F9AF-200D-27A1-FE0F", + "label": "person with white cane facing right", + "order": 2171, + "unicode": "🧑🏽‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F9AF-200D-27A1-FE0F", + "label": "person with white cane facing right", + "order": 2173, + "unicode": "🧑🏾‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F9AF-200D-27A1-FE0F", + "label": "person with white cane facing right", + "order": 2175, + "unicode": "🧑🏿‍🦯‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-1F9AF", + "label": "man with white cane", + "order": 2177, + "tags": ["accessibility", "blind", "cane", "man", "probing", "white"], + "unicode": "👨‍🦯", + "skins": [ + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F9AF", + "label": "man with white cane: light skin tone", + "order": 2178, + "unicode": "👨🏻‍🦯" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F9AF", + "label": "man with white cane: medium-light skin tone", + "order": 2179, + "unicode": "👨🏼‍🦯" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F9AF", + "label": "man with white cane: medium skin tone", + "order": 2180, + "unicode": "👨🏽‍🦯" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F9AF", + "label": "man with white cane: medium-dark skin tone", + "order": 2181, + "unicode": "👨🏾‍🦯" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F9AF", + "label": "man with white cane: dark skin tone", + "order": 2182, + "unicode": "👨🏿‍🦯" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-1F9AF-200D-27A1-FE0F", + "label": "man with white cane facing right", + "order": 2183, + "tags": ["accessibility", "blind", "cane", "man", "probing", "white"], + "unicode": "👨‍🦯‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F9AF-200D-27A1-FE0F", + "label": "man with white cane facing right", + "order": 2185, + "unicode": "👨🏻‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F9AF-200D-27A1-FE0F", + "label": "man with white cane facing right", + "order": 2187, + "unicode": "👨🏼‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F9AF-200D-27A1-FE0F", + "label": "man with white cane facing right", + "order": 2189, + "unicode": "👨🏽‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F9AF-200D-27A1-FE0F", + "label": "man with white cane facing right", + "order": 2191, + "unicode": "👨🏾‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F9AF-200D-27A1-FE0F", + "label": "man with white cane facing right", + "order": 2193, + "unicode": "👨🏿‍🦯‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-1F9AF", + "label": "woman with white cane", + "order": 2195, + "tags": ["accessibility", "blind", "cane", "probing", "white", "woman"], + "unicode": "👩‍🦯", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F9AF", + "label": "woman with white cane: light skin tone", + "order": 2196, + "unicode": "👩🏻‍🦯" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F9AF", + "label": "woman with white cane: medium-light skin tone", + "order": 2197, + "unicode": "👩🏼‍🦯" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F9AF", + "label": "woman with white cane: medium skin tone", + "order": 2198, + "unicode": "👩🏽‍🦯" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F9AF", + "label": "woman with white cane: medium-dark skin tone", + "order": 2199, + "unicode": "👩🏾‍🦯" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F9AF", + "label": "woman with white cane: dark skin tone", + "order": 2200, + "unicode": "👩🏿‍🦯" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-1F9AF-200D-27A1-FE0F", + "label": "woman with white cane facing right", + "order": 2201, + "tags": ["accessibility", "blind", "cane", "probing", "white", "woman"], + "unicode": "👩‍🦯‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F9AF-200D-27A1-FE0F", + "label": "woman with white cane facing right", + "order": 2203, + "unicode": "👩🏻‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F9AF-200D-27A1-FE0F", + "label": "woman with white cane facing right", + "order": 2205, + "unicode": "👩🏼‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F9AF-200D-27A1-FE0F", + "label": "woman with white cane facing right", + "order": 2207, + "unicode": "👩🏽‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F9AF-200D-27A1-FE0F", + "label": "woman with white cane facing right", + "order": 2209, + "unicode": "👩🏾‍🦯‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F9AF-200D-27A1-FE0F", + "label": "woman with white cane facing right", + "order": 2211, + "unicode": "👩🏿‍🦯‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9BC", + "label": "person in motorized wheelchair", + "order": 2213, + "tags": ["accessibility", "motorized", "person", "wheelchair"], + "unicode": "🧑‍🦼", + "skins": [ + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F9BC", + "label": "person in motorized wheelchair: light skin tone", + "order": 2214, + "unicode": "🧑🏻‍🦼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F9BC", + "label": "person in motorized wheelchair: medium-light skin tone", + "order": 2215, + "unicode": "🧑🏼‍🦼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F9BC", + "label": "person in motorized wheelchair: medium skin tone", + "order": 2216, + "unicode": "🧑🏽‍🦼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F9BC", + "label": "person in motorized wheelchair: medium-dark skin tone", + "order": 2217, + "unicode": "🧑🏾‍🦼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F9BC", + "label": "person in motorized wheelchair: dark skin tone", + "order": 2218, + "unicode": "🧑🏿‍🦼" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9BC-200D-27A1-FE0F", + "label": "person in motorized wheelchair facing right", + "order": 2219, + "tags": ["accessibility", "motorized", "person", "wheelchair"], + "unicode": "🧑‍🦼‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F9BC-200D-27A1-FE0F", + "label": "person in motorized wheelchair facing right", + "order": 2221, + "unicode": "🧑🏻‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F9BC-200D-27A1-FE0F", + "label": "person in motorized wheelchair facing right", + "order": 2223, + "unicode": "🧑🏼‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F9BC-200D-27A1-FE0F", + "label": "person in motorized wheelchair facing right", + "order": 2225, + "unicode": "🧑🏽‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F9BC-200D-27A1-FE0F", + "label": "person in motorized wheelchair facing right", + "order": 2227, + "unicode": "🧑🏾‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F9BC-200D-27A1-FE0F", + "label": "person in motorized wheelchair facing right", + "order": 2229, + "unicode": "🧑🏿‍🦼‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-1F9BC", + "label": "man in motorized wheelchair", + "order": 2231, + "tags": ["accessibility", "man", "motorized", "wheelchair"], + "unicode": "👨‍🦼", + "skins": [ + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F9BC", + "label": "man in motorized wheelchair: light skin tone", + "order": 2232, + "unicode": "👨🏻‍🦼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F9BC", + "label": "man in motorized wheelchair: medium-light skin tone", + "order": 2233, + "unicode": "👨🏼‍🦼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F9BC", + "label": "man in motorized wheelchair: medium skin tone", + "order": 2234, + "unicode": "👨🏽‍🦼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F9BC", + "label": "man in motorized wheelchair: medium-dark skin tone", + "order": 2235, + "unicode": "👨🏾‍🦼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F9BC", + "label": "man in motorized wheelchair: dark skin tone", + "order": 2236, + "unicode": "👨🏿‍🦼" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-1F9BC-200D-27A1-FE0F", + "label": "man in motorized wheelchair facing right", + "order": 2237, + "tags": ["accessibility", "man", "motorized", "wheelchair"], + "unicode": "👨‍🦼‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F9BC-200D-27A1-FE0F", + "label": "man in motorized wheelchair facing right", + "order": 2239, + "unicode": "👨🏻‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F9BC-200D-27A1-FE0F", + "label": "man in motorized wheelchair facing right", + "order": 2241, + "unicode": "👨🏼‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F9BC-200D-27A1-FE0F", + "label": "man in motorized wheelchair facing right", + "order": 2243, + "unicode": "👨🏽‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F9BC-200D-27A1-FE0F", + "label": "man in motorized wheelchair facing right", + "order": 2245, + "unicode": "👨🏾‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F9BC-200D-27A1-FE0F", + "label": "man in motorized wheelchair facing right", + "order": 2247, + "unicode": "👨🏿‍🦼‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-1F9BC", + "label": "woman in motorized wheelchair", + "order": 2249, + "tags": ["accessibility", "motorized", "wheelchair", "woman"], + "unicode": "👩‍🦼", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F9BC", + "label": "woman in motorized wheelchair: light skin tone", + "order": 2250, + "unicode": "👩🏻‍🦼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F9BC", + "label": "woman in motorized wheelchair: medium-light skin tone", + "order": 2251, + "unicode": "👩🏼‍🦼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F9BC", + "label": "woman in motorized wheelchair: medium skin tone", + "order": 2252, + "unicode": "👩🏽‍🦼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F9BC", + "label": "woman in motorized wheelchair: medium-dark skin tone", + "order": 2253, + "unicode": "👩🏾‍🦼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F9BC", + "label": "woman in motorized wheelchair: dark skin tone", + "order": 2254, + "unicode": "👩🏿‍🦼" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-1F9BC-200D-27A1-FE0F", + "label": "woman in motorized wheelchair facing right", + "order": 2255, + "tags": ["accessibility", "motorized", "wheelchair", "woman"], + "unicode": "👩‍🦼‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F9BC-200D-27A1-FE0F", + "label": "woman in motorized wheelchair facing right", + "order": 2257, + "unicode": "👩🏻‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F9BC-200D-27A1-FE0F", + "label": "woman in motorized wheelchair facing right", + "order": 2259, + "unicode": "👩🏼‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F9BC-200D-27A1-FE0F", + "label": "woman in motorized wheelchair facing right", + "order": 2261, + "unicode": "👩🏽‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F9BC-200D-27A1-FE0F", + "label": "woman in motorized wheelchair facing right", + "order": 2263, + "unicode": "👩🏾‍🦼‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F9BC-200D-27A1-FE0F", + "label": "woman in motorized wheelchair facing right", + "order": 2265, + "unicode": "👩🏿‍🦼‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9BD", + "label": "person in manual wheelchair", + "order": 2267, + "tags": ["accessibility", "manual", "person", "wheelchair"], + "unicode": "🧑‍🦽", + "skins": [ + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F9BD", + "label": "person in manual wheelchair: light skin tone", + "order": 2268, + "unicode": "🧑🏻‍🦽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F9BD", + "label": "person in manual wheelchair: medium-light skin tone", + "order": 2269, + "unicode": "🧑🏼‍🦽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F9BD", + "label": "person in manual wheelchair: medium skin tone", + "order": 2270, + "unicode": "🧑🏽‍🦽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F9BD", + "label": "person in manual wheelchair: medium-dark skin tone", + "order": 2271, + "unicode": "🧑🏾‍🦽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F9BD", + "label": "person in manual wheelchair: dark skin tone", + "order": 2272, + "unicode": "🧑🏿‍🦽" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9BD-200D-27A1-FE0F", + "label": "person in manual wheelchair facing right", + "order": 2273, + "tags": ["accessibility", "manual", "person", "wheelchair"], + "unicode": "🧑‍🦽‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F9BD-200D-27A1-FE0F", + "label": "person in manual wheelchair facing right", + "order": 2275, + "unicode": "🧑🏻‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F9BD-200D-27A1-FE0F", + "label": "person in manual wheelchair facing right", + "order": 2277, + "unicode": "🧑🏼‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F9BD-200D-27A1-FE0F", + "label": "person in manual wheelchair facing right", + "order": 2279, + "unicode": "🧑🏽‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F9BD-200D-27A1-FE0F", + "label": "person in manual wheelchair facing right", + "order": 2281, + "unicode": "🧑🏾‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F9BD-200D-27A1-FE0F", + "label": "person in manual wheelchair facing right", + "order": 2283, + "unicode": "🧑🏿‍🦽‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-1F9BD", + "label": "man in manual wheelchair", + "order": 2285, + "tags": ["accessibility", "man", "manual", "wheelchair"], + "unicode": "👨‍🦽", + "skins": [ + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F9BD", + "label": "man in manual wheelchair: light skin tone", + "order": 2286, + "unicode": "👨🏻‍🦽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F9BD", + "label": "man in manual wheelchair: medium-light skin tone", + "order": 2287, + "unicode": "👨🏼‍🦽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F9BD", + "label": "man in manual wheelchair: medium skin tone", + "order": 2288, + "unicode": "👨🏽‍🦽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F9BD", + "label": "man in manual wheelchair: medium-dark skin tone", + "order": 2289, + "unicode": "👨🏾‍🦽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F9BD", + "label": "man in manual wheelchair: dark skin tone", + "order": 2290, + "unicode": "👨🏿‍🦽" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-1F9BD-200D-27A1-FE0F", + "label": "man in manual wheelchair facing right", + "order": 2291, + "tags": ["accessibility", "man", "manual", "wheelchair"], + "unicode": "👨‍🦽‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F9BD-200D-27A1-FE0F", + "label": "man in manual wheelchair facing right", + "order": 2293, + "unicode": "👨🏻‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F9BD-200D-27A1-FE0F", + "label": "man in manual wheelchair facing right", + "order": 2295, + "unicode": "👨🏼‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F9BD-200D-27A1-FE0F", + "label": "man in manual wheelchair facing right", + "order": 2297, + "unicode": "👨🏽‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F9BD-200D-27A1-FE0F", + "label": "man in manual wheelchair facing right", + "order": 2299, + "unicode": "👨🏾‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F9BD-200D-27A1-FE0F", + "label": "man in manual wheelchair facing right", + "order": 2301, + "unicode": "👨🏿‍🦽‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-1F9BD", + "label": "woman in manual wheelchair", + "order": 2303, + "tags": ["accessibility", "manual", "wheelchair", "woman"], + "unicode": "👩‍🦽", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F9BD", + "label": "woman in manual wheelchair: light skin tone", + "order": 2304, + "unicode": "👩🏻‍🦽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F9BD", + "label": "woman in manual wheelchair: medium-light skin tone", + "order": 2305, + "unicode": "👩🏼‍🦽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F9BD", + "label": "woman in manual wheelchair: medium skin tone", + "order": 2306, + "unicode": "👩🏽‍🦽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F9BD", + "label": "woman in manual wheelchair: medium-dark skin tone", + "order": 2307, + "unicode": "👩🏾‍🦽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F9BD", + "label": "woman in manual wheelchair: dark skin tone", + "order": 2308, + "unicode": "👩🏿‍🦽" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-1F9BD-200D-27A1-FE0F", + "label": "woman in manual wheelchair facing right", + "order": 2309, + "tags": ["accessibility", "manual", "wheelchair", "woman"], + "unicode": "👩‍🦽‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F9BD-200D-27A1-FE0F", + "label": "woman in manual wheelchair facing right", + "order": 2311, + "unicode": "👩🏻‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F9BD-200D-27A1-FE0F", + "label": "woman in manual wheelchair facing right", + "order": 2313, + "unicode": "👩🏼‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F9BD-200D-27A1-FE0F", + "label": "woman in manual wheelchair facing right", + "order": 2315, + "unicode": "👩🏽‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F9BD-200D-27A1-FE0F", + "label": "woman in manual wheelchair facing right", + "order": 2317, + "unicode": "👩🏾‍🦽‍➡️" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F9BD-200D-27A1-FE0F", + "label": "woman in manual wheelchair facing right", + "order": 2319, + "unicode": "👩🏿‍🦽‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C3", + "label": "person running", + "order": 2321, + "tags": [ + "fast", + "hurry", + "marathon", + "move", + "person", + "quick", + "race", + "racing", + "run", + "rush", + "speed" + ], + "unicode": "🏃", + "skins": [ + { + "group": 1, + "hexcode": "1F3C3-1F3FB", + "label": "person running: light skin tone", + "order": 2322, + "unicode": "🏃🏻" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FC", + "label": "person running: medium-light skin tone", + "order": 2323, + "unicode": "🏃🏼" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FD", + "label": "person running: medium skin tone", + "order": 2324, + "unicode": "🏃🏽" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FE", + "label": "person running: medium-dark skin tone", + "order": 2325, + "unicode": "🏃🏾" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FF", + "label": "person running: dark skin tone", + "order": 2326, + "unicode": "🏃🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C3-200D-2642-FE0F", + "label": "man running", + "order": 2327, + "tags": [ + "fast", + "hurry", + "man", + "marathon", + "move", + "quick", + "race", + "racing", + "run", + "rush", + "speed" + ], + "unicode": "🏃‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C3-1F3FB-200D-2642-FE0F", + "label": "man running: light skin tone", + "order": 2329, + "unicode": "🏃🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FC-200D-2642-FE0F", + "label": "man running: medium-light skin tone", + "order": 2331, + "unicode": "🏃🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FD-200D-2642-FE0F", + "label": "man running: medium skin tone", + "order": 2333, + "unicode": "🏃🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FE-200D-2642-FE0F", + "label": "man running: medium-dark skin tone", + "order": 2335, + "unicode": "🏃🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FF-200D-2642-FE0F", + "label": "man running: dark skin tone", + "order": 2337, + "unicode": "🏃🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C3-200D-2640-FE0F", + "label": "woman running", + "order": 2339, + "tags": [ + "fast", + "hurry", + "marathon", + "move", + "quick", + "race", + "racing", + "run", + "rush", + "speed", + "woman" + ], + "unicode": "🏃‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C3-1F3FB-200D-2640-FE0F", + "label": "woman running: light skin tone", + "order": 2341, + "unicode": "🏃🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FC-200D-2640-FE0F", + "label": "woman running: medium-light skin tone", + "order": 2343, + "unicode": "🏃🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FD-200D-2640-FE0F", + "label": "woman running: medium skin tone", + "order": 2345, + "unicode": "🏃🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FE-200D-2640-FE0F", + "label": "woman running: medium-dark skin tone", + "order": 2347, + "unicode": "🏃🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FF-200D-2640-FE0F", + "label": "woman running: dark skin tone", + "order": 2349, + "unicode": "🏃🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C3-200D-27A1-FE0F", + "label": "person running facing right", + "order": 2351, + "tags": [ + "fast", + "hurry", + "marathon", + "move", + "person", + "quick", + "race", + "racing", + "run", + "rush", + "speed" + ], + "unicode": "🏃‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C3-1F3FB-200D-27A1-FE0F", + "label": "person running facing right", + "order": 2353, + "unicode": "🏃🏻‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FC-200D-27A1-FE0F", + "label": "person running facing right", + "order": 2355, + "unicode": "🏃🏼‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FD-200D-27A1-FE0F", + "label": "person running facing right", + "order": 2357, + "unicode": "🏃🏽‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FE-200D-27A1-FE0F", + "label": "person running facing right", + "order": 2359, + "unicode": "🏃🏾‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FF-200D-27A1-FE0F", + "label": "person running facing right", + "order": 2361, + "unicode": "🏃🏿‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C3-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman running facing right", + "order": 2363, + "tags": [ + "fast", + "hurry", + "marathon", + "move", + "quick", + "race", + "racing", + "run", + "rush", + "speed", + "woman" + ], + "unicode": "🏃‍♀️‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C3-1F3FB-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman running facing right", + "order": 2367, + "unicode": "🏃🏻‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FC-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman running facing right", + "order": 2371, + "unicode": "🏃🏼‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FD-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman running facing right", + "order": 2375, + "unicode": "🏃🏽‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FE-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman running facing right", + "order": 2379, + "unicode": "🏃🏾‍♀️‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FF-200D-2640-FE0F-200D-27A1-FE0F", + "label": "woman running facing right", + "order": 2383, + "unicode": "🏃🏿‍♀️‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C3-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man running facing right", + "order": 2387, + "tags": [ + "fast", + "hurry", + "man", + "marathon", + "move", + "quick", + "race", + "racing", + "run", + "rush", + "speed" + ], + "unicode": "🏃‍♂️‍➡️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C3-1F3FB-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man running facing right", + "order": 2391, + "unicode": "🏃🏻‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FC-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man running facing right", + "order": 2395, + "unicode": "🏃🏼‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FD-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man running facing right", + "order": 2399, + "unicode": "🏃🏽‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FE-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man running facing right", + "order": 2403, + "unicode": "🏃🏾‍♂️‍➡️" + }, + { + "group": 1, + "hexcode": "1F3C3-1F3FF-200D-2642-FE0F-200D-27A1-FE0F", + "label": "man running facing right", + "order": 2407, + "unicode": "🏃🏿‍♂️‍➡️" + } + ] + }, + { + "group": 1, + "hexcode": "1F483", + "label": "woman dancing", + "order": 2411, + "tags": [ + "dance", + "dancer", + "dancing", + "elegant", + "festive", + "flair", + "flamenco", + "groove", + "let’s", + "salsa", + "tango", + "woman" + ], + "unicode": "💃", + "skins": [ + { + "group": 1, + "hexcode": "1F483-1F3FB", + "label": "woman dancing: light skin tone", + "order": 2412, + "unicode": "💃🏻" + }, + { + "group": 1, + "hexcode": "1F483-1F3FC", + "label": "woman dancing: medium-light skin tone", + "order": 2413, + "unicode": "💃🏼" + }, + { + "group": 1, + "hexcode": "1F483-1F3FD", + "label": "woman dancing: medium skin tone", + "order": 2414, + "unicode": "💃🏽" + }, + { + "group": 1, + "hexcode": "1F483-1F3FE", + "label": "woman dancing: medium-dark skin tone", + "order": 2415, + "unicode": "💃🏾" + }, + { + "group": 1, + "hexcode": "1F483-1F3FF", + "label": "woman dancing: dark skin tone", + "order": 2416, + "unicode": "💃🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F57A", + "label": "man dancing", + "order": 2417, + "tags": [ + "dance", + "dancer", + "dancing", + "elegant", + "festive", + "flair", + "flamenco", + "groove", + "let’s", + "man", + "salsa", + "tango" + ], + "unicode": "🕺", + "skins": [ + { + "group": 1, + "hexcode": "1F57A-1F3FB", + "label": "man dancing: light skin tone", + "order": 2418, + "unicode": "🕺🏻" + }, + { + "group": 1, + "hexcode": "1F57A-1F3FC", + "label": "man dancing: medium-light skin tone", + "order": 2419, + "unicode": "🕺🏼" + }, + { + "group": 1, + "hexcode": "1F57A-1F3FD", + "label": "man dancing: medium skin tone", + "order": 2420, + "unicode": "🕺🏽" + }, + { + "group": 1, + "hexcode": "1F57A-1F3FE", + "label": "man dancing: medium-dark skin tone", + "order": 2421, + "unicode": "🕺🏾" + }, + { + "group": 1, + "hexcode": "1F57A-1F3FF", + "label": "man dancing: dark skin tone", + "order": 2422, + "unicode": "🕺🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F574", + "label": "person in suit levitating", + "order": 2424, + "tags": ["business", "levitating", "person", "suit"], + "unicode": "🕴️", + "skins": [ + { + "group": 1, + "hexcode": "1F574-1F3FB", + "label": "person in suit levitating: light skin tone", + "order": 2425, + "unicode": "🕴🏻" + }, + { + "group": 1, + "hexcode": "1F574-1F3FC", + "label": "person in suit levitating: medium-light skin tone", + "order": 2426, + "unicode": "🕴🏼" + }, + { + "group": 1, + "hexcode": "1F574-1F3FD", + "label": "person in suit levitating: medium skin tone", + "order": 2427, + "unicode": "🕴🏽" + }, + { + "group": 1, + "hexcode": "1F574-1F3FE", + "label": "person in suit levitating: medium-dark skin tone", + "order": 2428, + "unicode": "🕴🏾" + }, + { + "group": 1, + "hexcode": "1F574-1F3FF", + "label": "person in suit levitating: dark skin tone", + "order": 2429, + "unicode": "🕴🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F46F", + "label": "people with bunny ears", + "order": 2430, + "tags": [ + "bestie", + "bff", + "bunny", + "counterpart", + "dancer", + "double", + "ear", + "identical", + "pair", + "party", + "partying", + "people", + "soulmate", + "twin", + "twinsies" + ], + "unicode": "👯" + }, + { + "group": 1, + "hexcode": "1F46F-200D-2642-FE0F", + "label": "men with bunny ears", + "order": 2431, + "tags": [ + "bestie", + "bff", + "bunny", + "counterpart", + "dancer", + "double", + "ear", + "identical", + "men", + "pair", + "party", + "partying", + "people", + "soulmate", + "twin", + "twinsies" + ], + "unicode": "👯‍♂️" + }, + { + "group": 1, + "hexcode": "1F46F-200D-2640-FE0F", + "label": "women with bunny ears", + "order": 2433, + "tags": [ + "bestie", + "bff", + "bunny", + "counterpart", + "dancer", + "double", + "ear", + "identical", + "pair", + "party", + "partying", + "people", + "soulmate", + "twin", + "twinsies", + "women" + ], + "unicode": "👯‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D6", + "label": "person in steamy room", + "order": 2435, + "tags": [ + "day", + "luxurious", + "pamper", + "person", + "relax", + "room", + "sauna", + "spa", + "steam", + "steambath", + "unwind" + ], + "unicode": "🧖", + "skins": [ + { + "group": 1, + "hexcode": "1F9D6-1F3FB", + "label": "person in steamy room: light skin tone", + "order": 2436, + "unicode": "🧖🏻" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FC", + "label": "person in steamy room: medium-light skin tone", + "order": 2437, + "unicode": "🧖🏼" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FD", + "label": "person in steamy room: medium skin tone", + "order": 2438, + "unicode": "🧖🏽" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FE", + "label": "person in steamy room: medium-dark skin tone", + "order": 2439, + "unicode": "🧖🏾" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FF", + "label": "person in steamy room: dark skin tone", + "order": 2440, + "unicode": "🧖🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D6-200D-2642-FE0F", + "label": "man in steamy room", + "order": 2441, + "tags": [ + "day", + "luxurious", + "man", + "pamper", + "relax", + "room", + "sauna", + "spa", + "steam", + "steambath", + "unwind" + ], + "unicode": "🧖‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D6-1F3FB-200D-2642-FE0F", + "label": "man in steamy room: light skin tone", + "order": 2443, + "unicode": "🧖🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FC-200D-2642-FE0F", + "label": "man in steamy room: medium-light skin tone", + "order": 2445, + "unicode": "🧖🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FD-200D-2642-FE0F", + "label": "man in steamy room: medium skin tone", + "order": 2447, + "unicode": "🧖🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FE-200D-2642-FE0F", + "label": "man in steamy room: medium-dark skin tone", + "order": 2449, + "unicode": "🧖🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FF-200D-2642-FE0F", + "label": "man in steamy room: dark skin tone", + "order": 2451, + "unicode": "🧖🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D6-200D-2640-FE0F", + "label": "woman in steamy room", + "order": 2453, + "tags": [ + "day", + "luxurious", + "pamper", + "relax", + "room", + "sauna", + "spa", + "steam", + "steambath", + "unwind", + "woman" + ], + "unicode": "🧖‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D6-1F3FB-200D-2640-FE0F", + "label": "woman in steamy room: light skin tone", + "order": 2455, + "unicode": "🧖🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FC-200D-2640-FE0F", + "label": "woman in steamy room: medium-light skin tone", + "order": 2457, + "unicode": "🧖🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FD-200D-2640-FE0F", + "label": "woman in steamy room: medium skin tone", + "order": 2459, + "unicode": "🧖🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FE-200D-2640-FE0F", + "label": "woman in steamy room: medium-dark skin tone", + "order": 2461, + "unicode": "🧖🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D6-1F3FF-200D-2640-FE0F", + "label": "woman in steamy room: dark skin tone", + "order": 2463, + "unicode": "🧖🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D7", + "label": "person climbing", + "order": 2465, + "tags": [ + "climb", + "climber", + "climbing", + "mountain", + "person", + "rock", + "scale", + "up" + ], + "unicode": "🧗", + "skins": [ + { + "group": 1, + "hexcode": "1F9D7-1F3FB", + "label": "person climbing: light skin tone", + "order": 2466, + "unicode": "🧗🏻" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FC", + "label": "person climbing: medium-light skin tone", + "order": 2467, + "unicode": "🧗🏼" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FD", + "label": "person climbing: medium skin tone", + "order": 2468, + "unicode": "🧗🏽" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FE", + "label": "person climbing: medium-dark skin tone", + "order": 2469, + "unicode": "🧗🏾" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FF", + "label": "person climbing: dark skin tone", + "order": 2470, + "unicode": "🧗🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D7-200D-2642-FE0F", + "label": "man climbing", + "order": 2471, + "tags": [ + "climb", + "climber", + "climbing", + "man", + "mountain", + "rock", + "scale", + "up" + ], + "unicode": "🧗‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D7-1F3FB-200D-2642-FE0F", + "label": "man climbing: light skin tone", + "order": 2473, + "unicode": "🧗🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FC-200D-2642-FE0F", + "label": "man climbing: medium-light skin tone", + "order": 2475, + "unicode": "🧗🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FD-200D-2642-FE0F", + "label": "man climbing: medium skin tone", + "order": 2477, + "unicode": "🧗🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FE-200D-2642-FE0F", + "label": "man climbing: medium-dark skin tone", + "order": 2479, + "unicode": "🧗🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FF-200D-2642-FE0F", + "label": "man climbing: dark skin tone", + "order": 2481, + "unicode": "🧗🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D7-200D-2640-FE0F", + "label": "woman climbing", + "order": 2483, + "tags": [ + "climb", + "climber", + "climbing", + "mountain", + "rock", + "scale", + "up", + "woman" + ], + "unicode": "🧗‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D7-1F3FB-200D-2640-FE0F", + "label": "woman climbing: light skin tone", + "order": 2485, + "unicode": "🧗🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FC-200D-2640-FE0F", + "label": "woman climbing: medium-light skin tone", + "order": 2487, + "unicode": "🧗🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FD-200D-2640-FE0F", + "label": "woman climbing: medium skin tone", + "order": 2489, + "unicode": "🧗🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FE-200D-2640-FE0F", + "label": "woman climbing: medium-dark skin tone", + "order": 2491, + "unicode": "🧗🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D7-1F3FF-200D-2640-FE0F", + "label": "woman climbing: dark skin tone", + "order": 2493, + "unicode": "🧗🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F93A", + "label": "person fencing", + "order": 2495, + "tags": ["fencer", "fencing", "person", "sword"], + "unicode": "🤺" + }, + { + "group": 1, + "hexcode": "1F3C7", + "label": "horse racing", + "order": 2496, + "tags": ["horse", "jockey", "racehorse", "racing", "riding", "sport"], + "unicode": "🏇", + "skins": [ + { + "group": 1, + "hexcode": "1F3C7-1F3FB", + "label": "horse racing: light skin tone", + "order": 2497, + "unicode": "🏇🏻" + }, + { + "group": 1, + "hexcode": "1F3C7-1F3FC", + "label": "horse racing: medium-light skin tone", + "order": 2498, + "unicode": "🏇🏼" + }, + { + "group": 1, + "hexcode": "1F3C7-1F3FD", + "label": "horse racing: medium skin tone", + "order": 2499, + "unicode": "🏇🏽" + }, + { + "group": 1, + "hexcode": "1F3C7-1F3FE", + "label": "horse racing: medium-dark skin tone", + "order": 2500, + "unicode": "🏇🏾" + }, + { + "group": 1, + "hexcode": "1F3C7-1F3FF", + "label": "horse racing: dark skin tone", + "order": 2501, + "unicode": "🏇🏿" + } + ] + }, + { + "group": 1, + "hexcode": "26F7", + "label": "skier", + "order": 2503, + "tags": ["ski", "snow"], + "unicode": "⛷️" + }, + { + "group": 1, + "hexcode": "1F3C2", + "label": "snowboarder", + "order": 2504, + "tags": ["ski", "snow", "snowboard", "sport"], + "unicode": "🏂️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C2-1F3FB", + "label": "snowboarder: light skin tone", + "order": 2505, + "unicode": "🏂🏻" + }, + { + "group": 1, + "hexcode": "1F3C2-1F3FC", + "label": "snowboarder: medium-light skin tone", + "order": 2506, + "unicode": "🏂🏼" + }, + { + "group": 1, + "hexcode": "1F3C2-1F3FD", + "label": "snowboarder: medium skin tone", + "order": 2507, + "unicode": "🏂🏽" + }, + { + "group": 1, + "hexcode": "1F3C2-1F3FE", + "label": "snowboarder: medium-dark skin tone", + "order": 2508, + "unicode": "🏂🏾" + }, + { + "group": 1, + "hexcode": "1F3C2-1F3FF", + "label": "snowboarder: dark skin tone", + "order": 2509, + "unicode": "🏂🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CC", + "label": "person golfing", + "order": 2511, + "tags": [ + "ball", + "birdie", + "caddy", + "driving", + "golf", + "golfing", + "green", + "person", + "pga", + "putt", + "range", + "tee" + ], + "unicode": "🏌️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CC-1F3FB", + "label": "person golfing: light skin tone", + "order": 2512, + "unicode": "🏌🏻" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FC", + "label": "person golfing: medium-light skin tone", + "order": 2513, + "unicode": "🏌🏼" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FD", + "label": "person golfing: medium skin tone", + "order": 2514, + "unicode": "🏌🏽" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FE", + "label": "person golfing: medium-dark skin tone", + "order": 2515, + "unicode": "🏌🏾" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FF", + "label": "person golfing: dark skin tone", + "order": 2516, + "unicode": "🏌🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CC-FE0F-200D-2642-FE0F", + "label": "man golfing", + "order": 2517, + "tags": [ + "ball", + "birdie", + "caddy", + "driving", + "golf", + "golfing", + "green", + "man", + "pga", + "putt", + "range", + "tee" + ], + "unicode": "🏌️‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CC-1F3FB-200D-2642-FE0F", + "label": "man golfing: light skin tone", + "order": 2521, + "unicode": "🏌🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FC-200D-2642-FE0F", + "label": "man golfing: medium-light skin tone", + "order": 2523, + "unicode": "🏌🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FD-200D-2642-FE0F", + "label": "man golfing: medium skin tone", + "order": 2525, + "unicode": "🏌🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FE-200D-2642-FE0F", + "label": "man golfing: medium-dark skin tone", + "order": 2527, + "unicode": "🏌🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FF-200D-2642-FE0F", + "label": "man golfing: dark skin tone", + "order": 2529, + "unicode": "🏌🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CC-FE0F-200D-2640-FE0F", + "label": "woman golfing", + "order": 2531, + "tags": [ + "ball", + "birdie", + "caddy", + "driving", + "golf", + "golfing", + "green", + "pga", + "putt", + "range", + "tee", + "woman" + ], + "unicode": "🏌️‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CC-1F3FB-200D-2640-FE0F", + "label": "woman golfing: light skin tone", + "order": 2535, + "unicode": "🏌🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FC-200D-2640-FE0F", + "label": "woman golfing: medium-light skin tone", + "order": 2537, + "unicode": "🏌🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FD-200D-2640-FE0F", + "label": "woman golfing: medium skin tone", + "order": 2539, + "unicode": "🏌🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FE-200D-2640-FE0F", + "label": "woman golfing: medium-dark skin tone", + "order": 2541, + "unicode": "🏌🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CC-1F3FF-200D-2640-FE0F", + "label": "woman golfing: dark skin tone", + "order": 2543, + "unicode": "🏌🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C4", + "label": "person surfing", + "order": 2545, + "tags": [ + "beach", + "ocean", + "person", + "sport", + "surf", + "surfer", + "surfing", + "swell", + "waves" + ], + "unicode": "🏄️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C4-1F3FB", + "label": "person surfing: light skin tone", + "order": 2546, + "unicode": "🏄🏻" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FC", + "label": "person surfing: medium-light skin tone", + "order": 2547, + "unicode": "🏄🏼" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FD", + "label": "person surfing: medium skin tone", + "order": 2548, + "unicode": "🏄🏽" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FE", + "label": "person surfing: medium-dark skin tone", + "order": 2549, + "unicode": "🏄🏾" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FF", + "label": "person surfing: dark skin tone", + "order": 2550, + "unicode": "🏄🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C4-200D-2642-FE0F", + "label": "man surfing", + "order": 2551, + "tags": [ + "beach", + "man", + "ocean", + "sport", + "surf", + "surfer", + "surfing", + "swell", + "waves" + ], + "unicode": "🏄‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C4-1F3FB-200D-2642-FE0F", + "label": "man surfing: light skin tone", + "order": 2553, + "unicode": "🏄🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FC-200D-2642-FE0F", + "label": "man surfing: medium-light skin tone", + "order": 2555, + "unicode": "🏄🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FD-200D-2642-FE0F", + "label": "man surfing: medium skin tone", + "order": 2557, + "unicode": "🏄🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FE-200D-2642-FE0F", + "label": "man surfing: medium-dark skin tone", + "order": 2559, + "unicode": "🏄🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FF-200D-2642-FE0F", + "label": "man surfing: dark skin tone", + "order": 2561, + "unicode": "🏄🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3C4-200D-2640-FE0F", + "label": "woman surfing", + "order": 2563, + "tags": [ + "beach", + "ocean", + "person", + "sport", + "surf", + "surfer", + "surfing", + "swell", + "waves" + ], + "unicode": "🏄‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F3C4-1F3FB-200D-2640-FE0F", + "label": "woman surfing: light skin tone", + "order": 2565, + "unicode": "🏄🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FC-200D-2640-FE0F", + "label": "woman surfing: medium-light skin tone", + "order": 2567, + "unicode": "🏄🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FD-200D-2640-FE0F", + "label": "woman surfing: medium skin tone", + "order": 2569, + "unicode": "🏄🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FE-200D-2640-FE0F", + "label": "woman surfing: medium-dark skin tone", + "order": 2571, + "unicode": "🏄🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F3C4-1F3FF-200D-2640-FE0F", + "label": "woman surfing: dark skin tone", + "order": 2573, + "unicode": "🏄🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6A3", + "label": "person rowing boat", + "order": 2575, + "tags": [ + "boat", + "canoe", + "cruise", + "fishing", + "lake", + "oar", + "paddle", + "person", + "raft", + "river", + "row", + "rowboat", + "rowing" + ], + "unicode": "🚣", + "skins": [ + { + "group": 1, + "hexcode": "1F6A3-1F3FB", + "label": "person rowing boat: light skin tone", + "order": 2576, + "unicode": "🚣🏻" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FC", + "label": "person rowing boat: medium-light skin tone", + "order": 2577, + "unicode": "🚣🏼" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FD", + "label": "person rowing boat: medium skin tone", + "order": 2578, + "unicode": "🚣🏽" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FE", + "label": "person rowing boat: medium-dark skin tone", + "order": 2579, + "unicode": "🚣🏾" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FF", + "label": "person rowing boat: dark skin tone", + "order": 2580, + "unicode": "🚣🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F6A3-200D-2642-FE0F", + "label": "man rowing boat", + "order": 2581, + "tags": [ + "boat", + "canoe", + "cruise", + "fishing", + "lake", + "man", + "oar", + "paddle", + "raft", + "river", + "row", + "rowboat", + "rowing" + ], + "unicode": "🚣‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F6A3-1F3FB-200D-2642-FE0F", + "label": "man rowing boat: light skin tone", + "order": 2583, + "unicode": "🚣🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FC-200D-2642-FE0F", + "label": "man rowing boat: medium-light skin tone", + "order": 2585, + "unicode": "🚣🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FD-200D-2642-FE0F", + "label": "man rowing boat: medium skin tone", + "order": 2587, + "unicode": "🚣🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FE-200D-2642-FE0F", + "label": "man rowing boat: medium-dark skin tone", + "order": 2589, + "unicode": "🚣🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FF-200D-2642-FE0F", + "label": "man rowing boat: dark skin tone", + "order": 2591, + "unicode": "🚣🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6A3-200D-2640-FE0F", + "label": "woman rowing boat", + "order": 2593, + "tags": [ + "boat", + "canoe", + "cruise", + "fishing", + "lake", + "oar", + "paddle", + "raft", + "river", + "row", + "rowboat", + "rowing", + "woman" + ], + "unicode": "🚣‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F6A3-1F3FB-200D-2640-FE0F", + "label": "woman rowing boat: light skin tone", + "order": 2595, + "unicode": "🚣🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FC-200D-2640-FE0F", + "label": "woman rowing boat: medium-light skin tone", + "order": 2597, + "unicode": "🚣🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FD-200D-2640-FE0F", + "label": "woman rowing boat: medium skin tone", + "order": 2599, + "unicode": "🚣🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FE-200D-2640-FE0F", + "label": "woman rowing boat: medium-dark skin tone", + "order": 2601, + "unicode": "🚣🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F6A3-1F3FF-200D-2640-FE0F", + "label": "woman rowing boat: dark skin tone", + "order": 2603, + "unicode": "🚣🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CA", + "label": "person swimming", + "order": 2605, + "tags": [ + "freestyle", + "person", + "sport", + "swim", + "swimmer", + "swimming", + "triathlon" + ], + "unicode": "🏊️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CA-1F3FB", + "label": "person swimming: light skin tone", + "order": 2606, + "unicode": "🏊🏻" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FC", + "label": "person swimming: medium-light skin tone", + "order": 2607, + "unicode": "🏊🏼" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FD", + "label": "person swimming: medium skin tone", + "order": 2608, + "unicode": "🏊🏽" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FE", + "label": "person swimming: medium-dark skin tone", + "order": 2609, + "unicode": "🏊🏾" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FF", + "label": "person swimming: dark skin tone", + "order": 2610, + "unicode": "🏊🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CA-200D-2642-FE0F", + "label": "man swimming", + "order": 2611, + "tags": [ + "freestyle", + "man", + "sport", + "swim", + "swimmer", + "swimming", + "triathlon" + ], + "unicode": "🏊‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CA-1F3FB-200D-2642-FE0F", + "label": "man swimming: light skin tone", + "order": 2613, + "unicode": "🏊🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FC-200D-2642-FE0F", + "label": "man swimming: medium-light skin tone", + "order": 2615, + "unicode": "🏊🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FD-200D-2642-FE0F", + "label": "man swimming: medium skin tone", + "order": 2617, + "unicode": "🏊🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FE-200D-2642-FE0F", + "label": "man swimming: medium-dark skin tone", + "order": 2619, + "unicode": "🏊🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FF-200D-2642-FE0F", + "label": "man swimming: dark skin tone", + "order": 2621, + "unicode": "🏊🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CA-200D-2640-FE0F", + "label": "woman swimming", + "order": 2623, + "tags": [ + "freestyle", + "man", + "sport", + "swim", + "swimmer", + "swimming", + "triathlon" + ], + "unicode": "🏊‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CA-1F3FB-200D-2640-FE0F", + "label": "woman swimming: light skin tone", + "order": 2625, + "unicode": "🏊🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FC-200D-2640-FE0F", + "label": "woman swimming: medium-light skin tone", + "order": 2627, + "unicode": "🏊🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FD-200D-2640-FE0F", + "label": "woman swimming: medium skin tone", + "order": 2629, + "unicode": "🏊🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FE-200D-2640-FE0F", + "label": "woman swimming: medium-dark skin tone", + "order": 2631, + "unicode": "🏊🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CA-1F3FF-200D-2640-FE0F", + "label": "woman swimming: dark skin tone", + "order": 2633, + "unicode": "🏊🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "26F9", + "label": "person bouncing ball", + "order": 2636, + "tags": [ + "athletic", + "ball", + "basketball", + "bouncing", + "championship", + "dribble", + "net", + "person", + "player", + "throw" + ], + "unicode": "⛹️", + "skins": [ + { + "group": 1, + "hexcode": "26F9-1F3FB", + "label": "person bouncing ball: light skin tone", + "order": 2637, + "unicode": "⛹🏻" + }, + { + "group": 1, + "hexcode": "26F9-1F3FC", + "label": "person bouncing ball: medium-light skin tone", + "order": 2638, + "unicode": "⛹🏼" + }, + { + "group": 1, + "hexcode": "26F9-1F3FD", + "label": "person bouncing ball: medium skin tone", + "order": 2639, + "unicode": "⛹🏽" + }, + { + "group": 1, + "hexcode": "26F9-1F3FE", + "label": "person bouncing ball: medium-dark skin tone", + "order": 2640, + "unicode": "⛹🏾" + }, + { + "group": 1, + "hexcode": "26F9-1F3FF", + "label": "person bouncing ball: dark skin tone", + "order": 2641, + "unicode": "⛹🏿" + } + ] + }, + { + "group": 1, + "hexcode": "26F9-FE0F-200D-2642-FE0F", + "label": "man bouncing ball", + "order": 2642, + "tags": [ + "athletic", + "ball", + "basketball", + "bouncing", + "championship", + "dribble", + "man", + "net", + "player", + "throw" + ], + "unicode": "⛹️‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "26F9-1F3FB-200D-2642-FE0F", + "label": "man bouncing ball: light skin tone", + "order": 2646, + "unicode": "⛹🏻‍♂️" + }, + { + "group": 1, + "hexcode": "26F9-1F3FC-200D-2642-FE0F", + "label": "man bouncing ball: medium-light skin tone", + "order": 2648, + "unicode": "⛹🏼‍♂️" + }, + { + "group": 1, + "hexcode": "26F9-1F3FD-200D-2642-FE0F", + "label": "man bouncing ball: medium skin tone", + "order": 2650, + "unicode": "⛹🏽‍♂️" + }, + { + "group": 1, + "hexcode": "26F9-1F3FE-200D-2642-FE0F", + "label": "man bouncing ball: medium-dark skin tone", + "order": 2652, + "unicode": "⛹🏾‍♂️" + }, + { + "group": 1, + "hexcode": "26F9-1F3FF-200D-2642-FE0F", + "label": "man bouncing ball: dark skin tone", + "order": 2654, + "unicode": "⛹🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "26F9-FE0F-200D-2640-FE0F", + "label": "woman bouncing ball", + "order": 2656, + "tags": [ + "athletic", + "ball", + "basketball", + "bouncing", + "championship", + "dribble", + "net", + "player", + "throw", + "woman" + ], + "unicode": "⛹️‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "26F9-1F3FB-200D-2640-FE0F", + "label": "woman bouncing ball: light skin tone", + "order": 2660, + "unicode": "⛹🏻‍♀️" + }, + { + "group": 1, + "hexcode": "26F9-1F3FC-200D-2640-FE0F", + "label": "woman bouncing ball: medium-light skin tone", + "order": 2662, + "unicode": "⛹🏼‍♀️" + }, + { + "group": 1, + "hexcode": "26F9-1F3FD-200D-2640-FE0F", + "label": "woman bouncing ball: medium skin tone", + "order": 2664, + "unicode": "⛹🏽‍♀️" + }, + { + "group": 1, + "hexcode": "26F9-1F3FE-200D-2640-FE0F", + "label": "woman bouncing ball: medium-dark skin tone", + "order": 2666, + "unicode": "⛹🏾‍♀️" + }, + { + "group": 1, + "hexcode": "26F9-1F3FF-200D-2640-FE0F", + "label": "woman bouncing ball: dark skin tone", + "order": 2668, + "unicode": "⛹🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CB", + "label": "person lifting weights", + "order": 2671, + "tags": [ + "barbell", + "bodybuilder", + "deadlift", + "lifter", + "lifting", + "person", + "powerlifting", + "weight", + "weightlifter", + "weights", + "workout" + ], + "unicode": "🏋️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CB-1F3FB", + "label": "person lifting weights: light skin tone", + "order": 2672, + "unicode": "🏋🏻" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FC", + "label": "person lifting weights: medium-light skin tone", + "order": 2673, + "unicode": "🏋🏼" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FD", + "label": "person lifting weights: medium skin tone", + "order": 2674, + "unicode": "🏋🏽" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FE", + "label": "person lifting weights: medium-dark skin tone", + "order": 2675, + "unicode": "🏋🏾" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FF", + "label": "person lifting weights: dark skin tone", + "order": 2676, + "unicode": "🏋🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CB-FE0F-200D-2642-FE0F", + "label": "man lifting weights", + "order": 2677, + "tags": [ + "barbell", + "bodybuilder", + "deadlift", + "lifter", + "lifting", + "man", + "powerlifting", + "weight", + "weightlifter", + "weights", + "workout" + ], + "unicode": "🏋️‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CB-1F3FB-200D-2642-FE0F", + "label": "man lifting weights: light skin tone", + "order": 2681, + "unicode": "🏋🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FC-200D-2642-FE0F", + "label": "man lifting weights: medium-light skin tone", + "order": 2683, + "unicode": "🏋🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FD-200D-2642-FE0F", + "label": "man lifting weights: medium skin tone", + "order": 2685, + "unicode": "🏋🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FE-200D-2642-FE0F", + "label": "man lifting weights: medium-dark skin tone", + "order": 2687, + "unicode": "🏋🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FF-200D-2642-FE0F", + "label": "man lifting weights: dark skin tone", + "order": 2689, + "unicode": "🏋🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F3CB-FE0F-200D-2640-FE0F", + "label": "woman lifting weights", + "order": 2691, + "tags": [ + "barbell", + "bodybuilder", + "deadlift", + "lifter", + "lifting", + "powerlifting", + "weight", + "weightlifter", + "weights", + "woman", + "workout" + ], + "unicode": "🏋️‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F3CB-1F3FB-200D-2640-FE0F", + "label": "woman lifting weights: light skin tone", + "order": 2695, + "unicode": "🏋🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FC-200D-2640-FE0F", + "label": "woman lifting weights: medium-light skin tone", + "order": 2697, + "unicode": "🏋🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FD-200D-2640-FE0F", + "label": "woman lifting weights: medium skin tone", + "order": 2699, + "unicode": "🏋🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FE-200D-2640-FE0F", + "label": "woman lifting weights: medium-dark skin tone", + "order": 2701, + "unicode": "🏋🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F3CB-1F3FF-200D-2640-FE0F", + "label": "woman lifting weights: dark skin tone", + "order": 2703, + "unicode": "🏋🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B4", + "label": "person biking", + "order": 2705, + "tags": [ + "bicycle", + "bicyclist", + "bike", + "biking", + "cycle", + "cyclist", + "person", + "riding", + "sport" + ], + "unicode": "🚴", + "skins": [ + { + "group": 1, + "hexcode": "1F6B4-1F3FB", + "label": "person biking: light skin tone", + "order": 2706, + "unicode": "🚴🏻" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FC", + "label": "person biking: medium-light skin tone", + "order": 2707, + "unicode": "🚴🏼" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FD", + "label": "person biking: medium skin tone", + "order": 2708, + "unicode": "🚴🏽" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FE", + "label": "person biking: medium-dark skin tone", + "order": 2709, + "unicode": "🚴🏾" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FF", + "label": "person biking: dark skin tone", + "order": 2710, + "unicode": "🚴🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B4-200D-2642-FE0F", + "label": "man biking", + "order": 2711, + "tags": [ + "bicycle", + "bicyclist", + "bike", + "biking", + "cycle", + "cyclist", + "man", + "riding", + "sport" + ], + "unicode": "🚴‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B4-1F3FB-200D-2642-FE0F", + "label": "man biking: light skin tone", + "order": 2713, + "unicode": "🚴🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FC-200D-2642-FE0F", + "label": "man biking: medium-light skin tone", + "order": 2715, + "unicode": "🚴🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FD-200D-2642-FE0F", + "label": "man biking: medium skin tone", + "order": 2717, + "unicode": "🚴🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FE-200D-2642-FE0F", + "label": "man biking: medium-dark skin tone", + "order": 2719, + "unicode": "🚴🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FF-200D-2642-FE0F", + "label": "man biking: dark skin tone", + "order": 2721, + "unicode": "🚴🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B4-200D-2640-FE0F", + "label": "woman biking", + "order": 2723, + "tags": [ + "bicycle", + "bicyclist", + "bike", + "biking", + "cycle", + "cyclist", + "riding", + "sport", + "woman" + ], + "unicode": "🚴‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B4-1F3FB-200D-2640-FE0F", + "label": "woman biking: light skin tone", + "order": 2725, + "unicode": "🚴🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FC-200D-2640-FE0F", + "label": "woman biking: medium-light skin tone", + "order": 2727, + "unicode": "🚴🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FD-200D-2640-FE0F", + "label": "woman biking: medium skin tone", + "order": 2729, + "unicode": "🚴🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FE-200D-2640-FE0F", + "label": "woman biking: medium-dark skin tone", + "order": 2731, + "unicode": "🚴🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B4-1F3FF-200D-2640-FE0F", + "label": "woman biking: dark skin tone", + "order": 2733, + "unicode": "🚴🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B5", + "label": "person mountain biking", + "order": 2735, + "tags": [ + "bicycle", + "bicyclist", + "bike", + "biking", + "cycle", + "cyclist", + "mountain", + "person", + "riding", + "sport" + ], + "unicode": "🚵", + "skins": [ + { + "group": 1, + "hexcode": "1F6B5-1F3FB", + "label": "person mountain biking: light skin tone", + "order": 2736, + "unicode": "🚵🏻" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FC", + "label": "person mountain biking: medium-light skin tone", + "order": 2737, + "unicode": "🚵🏼" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FD", + "label": "person mountain biking: medium skin tone", + "order": 2738, + "unicode": "🚵🏽" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FE", + "label": "person mountain biking: medium-dark skin tone", + "order": 2739, + "unicode": "🚵🏾" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FF", + "label": "person mountain biking: dark skin tone", + "order": 2740, + "unicode": "🚵🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B5-200D-2642-FE0F", + "label": "man mountain biking", + "order": 2741, + "tags": [ + "bicycle", + "bicyclist", + "bike", + "biking", + "cycle", + "cyclist", + "man", + "mountain", + "riding", + "sport" + ], + "unicode": "🚵‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B5-1F3FB-200D-2642-FE0F", + "label": "man mountain biking: light skin tone", + "order": 2743, + "unicode": "🚵🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FC-200D-2642-FE0F", + "label": "man mountain biking: medium-light skin tone", + "order": 2745, + "unicode": "🚵🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FD-200D-2642-FE0F", + "label": "man mountain biking: medium skin tone", + "order": 2747, + "unicode": "🚵🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FE-200D-2642-FE0F", + "label": "man mountain biking: medium-dark skin tone", + "order": 2749, + "unicode": "🚵🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FF-200D-2642-FE0F", + "label": "man mountain biking: dark skin tone", + "order": 2751, + "unicode": "🚵🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6B5-200D-2640-FE0F", + "label": "woman mountain biking", + "order": 2753, + "tags": [ + "bicycle", + "bicyclist", + "bike", + "biking", + "cycle", + "cyclist", + "mountain", + "riding", + "sport", + "woman" + ], + "unicode": "🚵‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F6B5-1F3FB-200D-2640-FE0F", + "label": "woman mountain biking: light skin tone", + "order": 2755, + "unicode": "🚵🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FC-200D-2640-FE0F", + "label": "woman mountain biking: medium-light skin tone", + "order": 2757, + "unicode": "🚵🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FD-200D-2640-FE0F", + "label": "woman mountain biking: medium skin tone", + "order": 2759, + "unicode": "🚵🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FE-200D-2640-FE0F", + "label": "woman mountain biking: medium-dark skin tone", + "order": 2761, + "unicode": "🚵🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F6B5-1F3FF-200D-2640-FE0F", + "label": "woman mountain biking: dark skin tone", + "order": 2763, + "unicode": "🚵🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F938", + "label": "person cartwheeling", + "order": 2765, + "tags": [ + "active", + "cartwheel", + "cartwheeling", + "excited", + "flip", + "gymnastics", + "happy", + "person", + "somersault" + ], + "unicode": "🤸", + "skins": [ + { + "group": 1, + "hexcode": "1F938-1F3FB", + "label": "person cartwheeling: light skin tone", + "order": 2766, + "unicode": "🤸🏻" + }, + { + "group": 1, + "hexcode": "1F938-1F3FC", + "label": "person cartwheeling: medium-light skin tone", + "order": 2767, + "unicode": "🤸🏼" + }, + { + "group": 1, + "hexcode": "1F938-1F3FD", + "label": "person cartwheeling: medium skin tone", + "order": 2768, + "unicode": "🤸🏽" + }, + { + "group": 1, + "hexcode": "1F938-1F3FE", + "label": "person cartwheeling: medium-dark skin tone", + "order": 2769, + "unicode": "🤸🏾" + }, + { + "group": 1, + "hexcode": "1F938-1F3FF", + "label": "person cartwheeling: dark skin tone", + "order": 2770, + "unicode": "🤸🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F938-200D-2642-FE0F", + "label": "man cartwheeling", + "order": 2771, + "tags": [ + "active", + "cartwheel", + "cartwheeling", + "excited", + "flip", + "gymnastics", + "happy", + "man", + "somersault" + ], + "unicode": "🤸‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F938-1F3FB-200D-2642-FE0F", + "label": "man cartwheeling: light skin tone", + "order": 2773, + "unicode": "🤸🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F938-1F3FC-200D-2642-FE0F", + "label": "man cartwheeling: medium-light skin tone", + "order": 2775, + "unicode": "🤸🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F938-1F3FD-200D-2642-FE0F", + "label": "man cartwheeling: medium skin tone", + "order": 2777, + "unicode": "🤸🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F938-1F3FE-200D-2642-FE0F", + "label": "man cartwheeling: medium-dark skin tone", + "order": 2779, + "unicode": "🤸🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F938-1F3FF-200D-2642-FE0F", + "label": "man cartwheeling: dark skin tone", + "order": 2781, + "unicode": "🤸🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F938-200D-2640-FE0F", + "label": "woman cartwheeling", + "order": 2783, + "tags": [ + "active", + "cartwheel", + "cartwheeling", + "excited", + "flip", + "gymnastics", + "happy", + "somersault", + "woman" + ], + "unicode": "🤸‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F938-1F3FB-200D-2640-FE0F", + "label": "woman cartwheeling: light skin tone", + "order": 2785, + "unicode": "🤸🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F938-1F3FC-200D-2640-FE0F", + "label": "woman cartwheeling: medium-light skin tone", + "order": 2787, + "unicode": "🤸🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F938-1F3FD-200D-2640-FE0F", + "label": "woman cartwheeling: medium skin tone", + "order": 2789, + "unicode": "🤸🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F938-1F3FE-200D-2640-FE0F", + "label": "woman cartwheeling: medium-dark skin tone", + "order": 2791, + "unicode": "🤸🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F938-1F3FF-200D-2640-FE0F", + "label": "woman cartwheeling: dark skin tone", + "order": 2793, + "unicode": "🤸🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F93C", + "label": "people wrestling", + "order": 2795, + "tags": [ + "combat", + "duel", + "grapple", + "people", + "ring", + "tournament", + "wrestle", + "wrestling" + ], + "unicode": "🤼" + }, + { + "group": 1, + "hexcode": "1F93C-200D-2642-FE0F", + "label": "men wrestling", + "order": 2796, + "tags": [ + "combat", + "duel", + "grapple", + "men", + "ring", + "tournament", + "wrestle", + "wrestling" + ], + "unicode": "🤼‍♂️" + }, + { + "group": 1, + "hexcode": "1F93C-200D-2640-FE0F", + "label": "women wrestling", + "order": 2798, + "tags": [ + "combat", + "duel", + "grapple", + "ring", + "tournament", + "women", + "wrestle", + "wrestling" + ], + "unicode": "🤼‍♀️" + }, + { + "group": 1, + "hexcode": "1F93D", + "label": "person playing water polo", + "order": 2800, + "tags": [ + "person", + "playing", + "polo", + "sport", + "swimming", + "water", + "waterpolo" + ], + "unicode": "🤽", + "skins": [ + { + "group": 1, + "hexcode": "1F93D-1F3FB", + "label": "person playing water polo: light skin tone", + "order": 2801, + "unicode": "🤽🏻" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FC", + "label": "person playing water polo: medium-light skin tone", + "order": 2802, + "unicode": "🤽🏼" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FD", + "label": "person playing water polo: medium skin tone", + "order": 2803, + "unicode": "🤽🏽" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FE", + "label": "person playing water polo: medium-dark skin tone", + "order": 2804, + "unicode": "🤽🏾" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FF", + "label": "person playing water polo: dark skin tone", + "order": 2805, + "unicode": "🤽🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F93D-200D-2642-FE0F", + "label": "man playing water polo", + "order": 2806, + "tags": [ + "man", + "playing", + "polo", + "sport", + "swimming", + "water", + "waterpolo" + ], + "unicode": "🤽‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F93D-1F3FB-200D-2642-FE0F", + "label": "man playing water polo: light skin tone", + "order": 2808, + "unicode": "🤽🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FC-200D-2642-FE0F", + "label": "man playing water polo: medium-light skin tone", + "order": 2810, + "unicode": "🤽🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FD-200D-2642-FE0F", + "label": "man playing water polo: medium skin tone", + "order": 2812, + "unicode": "🤽🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FE-200D-2642-FE0F", + "label": "man playing water polo: medium-dark skin tone", + "order": 2814, + "unicode": "🤽🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FF-200D-2642-FE0F", + "label": "man playing water polo: dark skin tone", + "order": 2816, + "unicode": "🤽🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F93D-200D-2640-FE0F", + "label": "woman playing water polo", + "order": 2818, + "tags": [ + "playing", + "polo", + "sport", + "swimming", + "water", + "waterpolo", + "woman" + ], + "unicode": "🤽‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F93D-1F3FB-200D-2640-FE0F", + "label": "woman playing water polo: light skin tone", + "order": 2820, + "unicode": "🤽🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FC-200D-2640-FE0F", + "label": "woman playing water polo: medium-light skin tone", + "order": 2822, + "unicode": "🤽🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FD-200D-2640-FE0F", + "label": "woman playing water polo: medium skin tone", + "order": 2824, + "unicode": "🤽🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FE-200D-2640-FE0F", + "label": "woman playing water polo: medium-dark skin tone", + "order": 2826, + "unicode": "🤽🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F93D-1F3FF-200D-2640-FE0F", + "label": "woman playing water polo: dark skin tone", + "order": 2828, + "unicode": "🤽🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F93E", + "label": "person playing handball", + "order": 2830, + "tags": [ + "athletics", + "ball", + "catch", + "chuck", + "handball", + "hurl", + "lob", + "person", + "pitch", + "playing", + "sport", + "throw", + "toss" + ], + "unicode": "🤾", + "skins": [ + { + "group": 1, + "hexcode": "1F93E-1F3FB", + "label": "person playing handball: light skin tone", + "order": 2831, + "unicode": "🤾🏻" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FC", + "label": "person playing handball: medium-light skin tone", + "order": 2832, + "unicode": "🤾🏼" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FD", + "label": "person playing handball: medium skin tone", + "order": 2833, + "unicode": "🤾🏽" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FE", + "label": "person playing handball: medium-dark skin tone", + "order": 2834, + "unicode": "🤾🏾" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FF", + "label": "person playing handball: dark skin tone", + "order": 2835, + "unicode": "🤾🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F93E-200D-2642-FE0F", + "label": "man playing handball", + "order": 2836, + "tags": [ + "athletics", + "ball", + "catch", + "chuck", + "handball", + "hurl", + "lob", + "man", + "pitch", + "playing", + "sport", + "throw", + "toss" + ], + "unicode": "🤾‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F93E-1F3FB-200D-2642-FE0F", + "label": "man playing handball: light skin tone", + "order": 2838, + "unicode": "🤾🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FC-200D-2642-FE0F", + "label": "man playing handball: medium-light skin tone", + "order": 2840, + "unicode": "🤾🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FD-200D-2642-FE0F", + "label": "man playing handball: medium skin tone", + "order": 2842, + "unicode": "🤾🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FE-200D-2642-FE0F", + "label": "man playing handball: medium-dark skin tone", + "order": 2844, + "unicode": "🤾🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FF-200D-2642-FE0F", + "label": "man playing handball: dark skin tone", + "order": 2846, + "unicode": "🤾🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F93E-200D-2640-FE0F", + "label": "woman playing handball", + "order": 2848, + "tags": [ + "athletics", + "ball", + "catch", + "chuck", + "handball", + "hurl", + "lob", + "pitch", + "playing", + "sport", + "throw", + "toss", + "woman" + ], + "unicode": "🤾‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F93E-1F3FB-200D-2640-FE0F", + "label": "woman playing handball: light skin tone", + "order": 2850, + "unicode": "🤾🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FC-200D-2640-FE0F", + "label": "woman playing handball: medium-light skin tone", + "order": 2852, + "unicode": "🤾🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FD-200D-2640-FE0F", + "label": "woman playing handball: medium skin tone", + "order": 2854, + "unicode": "🤾🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FE-200D-2640-FE0F", + "label": "woman playing handball: medium-dark skin tone", + "order": 2856, + "unicode": "🤾🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F93E-1F3FF-200D-2640-FE0F", + "label": "woman playing handball: dark skin tone", + "order": 2858, + "unicode": "🤾🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F939", + "label": "person juggling", + "order": 2860, + "tags": [ + "act", + "balance", + "balancing", + "handle", + "juggle", + "juggling", + "manage", + "multitask", + "person", + "skill" + ], + "unicode": "🤹", + "skins": [ + { + "group": 1, + "hexcode": "1F939-1F3FB", + "label": "person juggling: light skin tone", + "order": 2861, + "unicode": "🤹🏻" + }, + { + "group": 1, + "hexcode": "1F939-1F3FC", + "label": "person juggling: medium-light skin tone", + "order": 2862, + "unicode": "🤹🏼" + }, + { + "group": 1, + "hexcode": "1F939-1F3FD", + "label": "person juggling: medium skin tone", + "order": 2863, + "unicode": "🤹🏽" + }, + { + "group": 1, + "hexcode": "1F939-1F3FE", + "label": "person juggling: medium-dark skin tone", + "order": 2864, + "unicode": "🤹🏾" + }, + { + "group": 1, + "hexcode": "1F939-1F3FF", + "label": "person juggling: dark skin tone", + "order": 2865, + "unicode": "🤹🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F939-200D-2642-FE0F", + "label": "man juggling", + "order": 2866, + "tags": [ + "act", + "balance", + "balancing", + "handle", + "juggle", + "juggling", + "man", + "manage", + "multitask", + "skill" + ], + "unicode": "🤹‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F939-1F3FB-200D-2642-FE0F", + "label": "man juggling: light skin tone", + "order": 2868, + "unicode": "🤹🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F939-1F3FC-200D-2642-FE0F", + "label": "man juggling: medium-light skin tone", + "order": 2870, + "unicode": "🤹🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F939-1F3FD-200D-2642-FE0F", + "label": "man juggling: medium skin tone", + "order": 2872, + "unicode": "🤹🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F939-1F3FE-200D-2642-FE0F", + "label": "man juggling: medium-dark skin tone", + "order": 2874, + "unicode": "🤹🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F939-1F3FF-200D-2642-FE0F", + "label": "man juggling: dark skin tone", + "order": 2876, + "unicode": "🤹🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F939-200D-2640-FE0F", + "label": "woman juggling", + "order": 2878, + "tags": [ + "act", + "balance", + "balancing", + "handle", + "juggle", + "juggling", + "manage", + "multitask", + "skill", + "woman" + ], + "unicode": "🤹‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F939-1F3FB-200D-2640-FE0F", + "label": "woman juggling: light skin tone", + "order": 2880, + "unicode": "🤹🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F939-1F3FC-200D-2640-FE0F", + "label": "woman juggling: medium-light skin tone", + "order": 2882, + "unicode": "🤹🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F939-1F3FD-200D-2640-FE0F", + "label": "woman juggling: medium skin tone", + "order": 2884, + "unicode": "🤹🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F939-1F3FE-200D-2640-FE0F", + "label": "woman juggling: medium-dark skin tone", + "order": 2886, + "unicode": "🤹🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F939-1F3FF-200D-2640-FE0F", + "label": "woman juggling: dark skin tone", + "order": 2888, + "unicode": "🤹🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D8", + "label": "person in lotus position", + "order": 2890, + "tags": [ + "cross", + "legged", + "legs", + "lotus", + "meditation", + "peace", + "person", + "position", + "relax", + "serenity", + "yoga", + "yogi", + "zen" + ], + "unicode": "🧘", + "skins": [ + { + "group": 1, + "hexcode": "1F9D8-1F3FB", + "label": "person in lotus position: light skin tone", + "order": 2891, + "unicode": "🧘🏻" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FC", + "label": "person in lotus position: medium-light skin tone", + "order": 2892, + "unicode": "🧘🏼" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FD", + "label": "person in lotus position: medium skin tone", + "order": 2893, + "unicode": "🧘🏽" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FE", + "label": "person in lotus position: medium-dark skin tone", + "order": 2894, + "unicode": "🧘🏾" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FF", + "label": "person in lotus position: dark skin tone", + "order": 2895, + "unicode": "🧘🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D8-200D-2642-FE0F", + "label": "man in lotus position", + "order": 2896, + "tags": [ + "cross", + "legged", + "legs", + "lotus", + "man", + "meditation", + "peace", + "position", + "relax", + "serenity", + "yoga", + "yogi", + "zen" + ], + "unicode": "🧘‍♂️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D8-1F3FB-200D-2642-FE0F", + "label": "man in lotus position: light skin tone", + "order": 2898, + "unicode": "🧘🏻‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FC-200D-2642-FE0F", + "label": "man in lotus position: medium-light skin tone", + "order": 2900, + "unicode": "🧘🏼‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FD-200D-2642-FE0F", + "label": "man in lotus position: medium skin tone", + "order": 2902, + "unicode": "🧘🏽‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FE-200D-2642-FE0F", + "label": "man in lotus position: medium-dark skin tone", + "order": 2904, + "unicode": "🧘🏾‍♂️" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FF-200D-2642-FE0F", + "label": "man in lotus position: dark skin tone", + "order": 2906, + "unicode": "🧘🏿‍♂️" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D8-200D-2640-FE0F", + "label": "woman in lotus position", + "order": 2908, + "tags": [ + "cross", + "legged", + "legs", + "lotus", + "meditation", + "peace", + "position", + "relax", + "serenity", + "woman", + "yoga", + "yogi", + "zen" + ], + "unicode": "🧘‍♀️", + "skins": [ + { + "group": 1, + "hexcode": "1F9D8-1F3FB-200D-2640-FE0F", + "label": "woman in lotus position: light skin tone", + "order": 2910, + "unicode": "🧘🏻‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FC-200D-2640-FE0F", + "label": "woman in lotus position: medium-light skin tone", + "order": 2912, + "unicode": "🧘🏼‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FD-200D-2640-FE0F", + "label": "woman in lotus position: medium skin tone", + "order": 2914, + "unicode": "🧘🏽‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FE-200D-2640-FE0F", + "label": "woman in lotus position: medium-dark skin tone", + "order": 2916, + "unicode": "🧘🏾‍♀️" + }, + { + "group": 1, + "hexcode": "1F9D8-1F3FF-200D-2640-FE0F", + "label": "woman in lotus position: dark skin tone", + "order": 2918, + "unicode": "🧘🏿‍♀️" + } + ] + }, + { + "group": 1, + "hexcode": "1F6C0", + "label": "person taking bath", + "order": 2920, + "tags": ["bath", "bathtub", "person", "taking", "tub"], + "unicode": "🛀", + "skins": [ + { + "group": 1, + "hexcode": "1F6C0-1F3FB", + "label": "person taking bath: light skin tone", + "order": 2921, + "unicode": "🛀🏻" + }, + { + "group": 1, + "hexcode": "1F6C0-1F3FC", + "label": "person taking bath: medium-light skin tone", + "order": 2922, + "unicode": "🛀🏼" + }, + { + "group": 1, + "hexcode": "1F6C0-1F3FD", + "label": "person taking bath: medium skin tone", + "order": 2923, + "unicode": "🛀🏽" + }, + { + "group": 1, + "hexcode": "1F6C0-1F3FE", + "label": "person taking bath: medium-dark skin tone", + "order": 2924, + "unicode": "🛀🏾" + }, + { + "group": 1, + "hexcode": "1F6C0-1F3FF", + "label": "person taking bath: dark skin tone", + "order": 2925, + "unicode": "🛀🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F6CC", + "label": "person in bed", + "order": 2926, + "tags": [ + "bed", + "bedtime", + "good", + "goodnight", + "hotel", + "nap", + "night", + "person", + "sleep", + "tired", + "zzz" + ], + "unicode": "🛌", + "skins": [ + { + "group": 1, + "hexcode": "1F6CC-1F3FB", + "label": "person in bed: light skin tone", + "order": 2927, + "unicode": "🛌🏻" + }, + { + "group": 1, + "hexcode": "1F6CC-1F3FC", + "label": "person in bed: medium-light skin tone", + "order": 2928, + "unicode": "🛌🏼" + }, + { + "group": 1, + "hexcode": "1F6CC-1F3FD", + "label": "person in bed: medium skin tone", + "order": 2929, + "unicode": "🛌🏽" + }, + { + "group": 1, + "hexcode": "1F6CC-1F3FE", + "label": "person in bed: medium-dark skin tone", + "order": 2930, + "unicode": "🛌🏾" + }, + { + "group": 1, + "hexcode": "1F6CC-1F3FF", + "label": "person in bed: dark skin tone", + "order": 2931, + "unicode": "🛌🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F91D-200D-1F9D1", + "label": "people holding hands", + "order": 2932, + "tags": [ + "bae", + "bestie", + "bff", + "couple", + "dating", + "flirt", + "friends", + "hand", + "hold", + "people", + "twins" + ], + "unicode": "🧑‍🤝‍🧑", + "skins": [ + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F91D-200D-1F9D1-1F3FB", + "label": "people holding hands: light skin tone", + "order": 2933, + "unicode": "🧑🏻‍🤝‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F91D-200D-1F9D1-1F3FC", + "label": "people holding hands: light skin tone, medium-light skin tone", + "order": 2934, + "unicode": "🧑🏻‍🤝‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F91D-200D-1F9D1-1F3FD", + "label": "people holding hands: light skin tone, medium skin tone", + "order": 2935, + "unicode": "🧑🏻‍🤝‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F91D-200D-1F9D1-1F3FE", + "label": "people holding hands: light skin tone, medium-dark skin tone", + "order": 2936, + "unicode": "🧑🏻‍🤝‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-1F91D-200D-1F9D1-1F3FF", + "label": "people holding hands: light skin tone, dark skin tone", + "order": 2937, + "unicode": "🧑🏻‍🤝‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F91D-200D-1F9D1-1F3FB", + "label": "people holding hands: medium-light skin tone, light skin tone", + "order": 2938, + "unicode": "🧑🏼‍🤝‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F91D-200D-1F9D1-1F3FC", + "label": "people holding hands: medium-light skin tone", + "order": 2939, + "unicode": "🧑🏼‍🤝‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F91D-200D-1F9D1-1F3FD", + "label": "people holding hands: medium-light skin tone, medium skin tone", + "order": 2940, + "unicode": "🧑🏼‍🤝‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F91D-200D-1F9D1-1F3FE", + "label": "people holding hands: medium-light skin tone, medium-dark skin tone", + "order": 2941, + "unicode": "🧑🏼‍🤝‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-1F91D-200D-1F9D1-1F3FF", + "label": "people holding hands: medium-light skin tone, dark skin tone", + "order": 2942, + "unicode": "🧑🏼‍🤝‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F91D-200D-1F9D1-1F3FB", + "label": "people holding hands: medium skin tone, light skin tone", + "order": 2943, + "unicode": "🧑🏽‍🤝‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F91D-200D-1F9D1-1F3FC", + "label": "people holding hands: medium skin tone, medium-light skin tone", + "order": 2944, + "unicode": "🧑🏽‍🤝‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F91D-200D-1F9D1-1F3FD", + "label": "people holding hands: medium skin tone", + "order": 2945, + "unicode": "🧑🏽‍🤝‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F91D-200D-1F9D1-1F3FE", + "label": "people holding hands: medium skin tone, medium-dark skin tone", + "order": 2946, + "unicode": "🧑🏽‍🤝‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-1F91D-200D-1F9D1-1F3FF", + "label": "people holding hands: medium skin tone, dark skin tone", + "order": 2947, + "unicode": "🧑🏽‍🤝‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F91D-200D-1F9D1-1F3FB", + "label": "people holding hands: medium-dark skin tone, light skin tone", + "order": 2948, + "unicode": "🧑🏾‍🤝‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F91D-200D-1F9D1-1F3FC", + "label": "people holding hands: medium-dark skin tone, medium-light skin tone", + "order": 2949, + "unicode": "🧑🏾‍🤝‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F91D-200D-1F9D1-1F3FD", + "label": "people holding hands: medium-dark skin tone, medium skin tone", + "order": 2950, + "unicode": "🧑🏾‍🤝‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F91D-200D-1F9D1-1F3FE", + "label": "people holding hands: medium-dark skin tone", + "order": 2951, + "unicode": "🧑🏾‍🤝‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-1F91D-200D-1F9D1-1F3FF", + "label": "people holding hands: medium-dark skin tone, dark skin tone", + "order": 2952, + "unicode": "🧑🏾‍🤝‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F91D-200D-1F9D1-1F3FB", + "label": "people holding hands: dark skin tone, light skin tone", + "order": 2953, + "unicode": "🧑🏿‍🤝‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F91D-200D-1F9D1-1F3FC", + "label": "people holding hands: dark skin tone, medium-light skin tone", + "order": 2954, + "unicode": "🧑🏿‍🤝‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F91D-200D-1F9D1-1F3FD", + "label": "people holding hands: dark skin tone, medium skin tone", + "order": 2955, + "unicode": "🧑🏿‍🤝‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F91D-200D-1F9D1-1F3FE", + "label": "people holding hands: dark skin tone, medium-dark skin tone", + "order": 2956, + "unicode": "🧑🏿‍🤝‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-1F91D-200D-1F9D1-1F3FF", + "label": "people holding hands: dark skin tone", + "order": 2957, + "unicode": "🧑🏿‍🤝‍🧑🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F46D", + "label": "women holding hands", + "order": 2958, + "tags": [ + "bae", + "bestie", + "bff", + "couple", + "dating", + "flirt", + "friends", + "girls", + "hand", + "hold", + "sisters", + "twins", + "women" + ], + "unicode": "👭", + "skins": [ + { + "group": 1, + "hexcode": "1F46D-1F3FB", + "label": "women holding hands: light skin tone", + "order": 2959, + "unicode": "👭🏻" + }, + { + "group": 1, + "hexcode": "1F46D-1F3FC", + "label": "women holding hands: medium-light skin tone", + "order": 2965, + "unicode": "👭🏼" + }, + { + "group": 1, + "hexcode": "1F46D-1F3FD", + "label": "women holding hands: medium skin tone", + "order": 2971, + "unicode": "👭🏽" + }, + { + "group": 1, + "hexcode": "1F46D-1F3FE", + "label": "women holding hands: medium-dark skin tone", + "order": 2977, + "unicode": "👭🏾" + }, + { + "group": 1, + "hexcode": "1F46D-1F3FF", + "label": "women holding hands: dark skin tone", + "order": 2983, + "unicode": "👭🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F91D-200D-1F469-1F3FC", + "label": "women holding hands: light skin tone, medium-light skin tone", + "order": 2960, + "unicode": "👩🏻‍🤝‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F91D-200D-1F469-1F3FD", + "label": "women holding hands: light skin tone, medium skin tone", + "order": 2961, + "unicode": "👩🏻‍🤝‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F91D-200D-1F469-1F3FE", + "label": "women holding hands: light skin tone, medium-dark skin tone", + "order": 2962, + "unicode": "👩🏻‍🤝‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F91D-200D-1F469-1F3FF", + "label": "women holding hands: light skin tone, dark skin tone", + "order": 2963, + "unicode": "👩🏻‍🤝‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F91D-200D-1F469-1F3FB", + "label": "women holding hands: medium-light skin tone, light skin tone", + "order": 2964, + "unicode": "👩🏼‍🤝‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F91D-200D-1F469-1F3FD", + "label": "women holding hands: medium-light skin tone, medium skin tone", + "order": 2966, + "unicode": "👩🏼‍🤝‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F91D-200D-1F469-1F3FE", + "label": "women holding hands: medium-light skin tone, medium-dark skin tone", + "order": 2967, + "unicode": "👩🏼‍🤝‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F91D-200D-1F469-1F3FF", + "label": "women holding hands: medium-light skin tone, dark skin tone", + "order": 2968, + "unicode": "👩🏼‍🤝‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F91D-200D-1F469-1F3FB", + "label": "women holding hands: medium skin tone, light skin tone", + "order": 2969, + "unicode": "👩🏽‍🤝‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F91D-200D-1F469-1F3FC", + "label": "women holding hands: medium skin tone, medium-light skin tone", + "order": 2970, + "unicode": "👩🏽‍🤝‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F91D-200D-1F469-1F3FE", + "label": "women holding hands: medium skin tone, medium-dark skin tone", + "order": 2972, + "unicode": "👩🏽‍🤝‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F91D-200D-1F469-1F3FF", + "label": "women holding hands: medium skin tone, dark skin tone", + "order": 2973, + "unicode": "👩🏽‍🤝‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F91D-200D-1F469-1F3FB", + "label": "women holding hands: medium-dark skin tone, light skin tone", + "order": 2974, + "unicode": "👩🏾‍🤝‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F91D-200D-1F469-1F3FC", + "label": "women holding hands: medium-dark skin tone, medium-light skin tone", + "order": 2975, + "unicode": "👩🏾‍🤝‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F91D-200D-1F469-1F3FD", + "label": "women holding hands: medium-dark skin tone, medium skin tone", + "order": 2976, + "unicode": "👩🏾‍🤝‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F91D-200D-1F469-1F3FF", + "label": "women holding hands: medium-dark skin tone, dark skin tone", + "order": 2978, + "unicode": "👩🏾‍🤝‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F91D-200D-1F469-1F3FB", + "label": "women holding hands: dark skin tone, light skin tone", + "order": 2979, + "unicode": "👩🏿‍🤝‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F91D-200D-1F469-1F3FC", + "label": "women holding hands: dark skin tone, medium-light skin tone", + "order": 2980, + "unicode": "👩🏿‍🤝‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F91D-200D-1F469-1F3FD", + "label": "women holding hands: dark skin tone, medium skin tone", + "order": 2981, + "unicode": "👩🏿‍🤝‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F91D-200D-1F469-1F3FE", + "label": "women holding hands: dark skin tone, medium-dark skin tone", + "order": 2982, + "unicode": "👩🏿‍🤝‍👩🏾" + } + ] + }, + { + "group": 1, + "hexcode": "1F46B", + "label": "woman and man holding hands", + "order": 2984, + "tags": [ + "bae", + "bestie", + "bff", + "couple", + "dating", + "flirt", + "friends", + "hand", + "hold", + "man", + "twins", + "woman" + ], + "unicode": "👫", + "skins": [ + { + "group": 1, + "hexcode": "1F46B-1F3FB", + "label": "woman and man holding hands: light skin tone", + "order": 2985, + "unicode": "👫🏻" + }, + { + "group": 1, + "hexcode": "1F46B-1F3FC", + "label": "woman and man holding hands: medium-light skin tone", + "order": 2991, + "unicode": "👫🏼" + }, + { + "group": 1, + "hexcode": "1F46B-1F3FD", + "label": "woman and man holding hands: medium skin tone", + "order": 2997, + "unicode": "👫🏽" + }, + { + "group": 1, + "hexcode": "1F46B-1F3FE", + "label": "woman and man holding hands: medium-dark skin tone", + "order": 3003, + "unicode": "👫🏾" + }, + { + "group": 1, + "hexcode": "1F46B-1F3FF", + "label": "woman and man holding hands: dark skin tone", + "order": 3009, + "unicode": "👫🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F91D-200D-1F468-1F3FC", + "label": "woman and man holding hands: light skin tone, medium-light skin tone", + "order": 2986, + "unicode": "👩🏻‍🤝‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F91D-200D-1F468-1F3FD", + "label": "woman and man holding hands: light skin tone, medium skin tone", + "order": 2987, + "unicode": "👩🏻‍🤝‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F91D-200D-1F468-1F3FE", + "label": "woman and man holding hands: light skin tone, medium-dark skin tone", + "order": 2988, + "unicode": "👩🏻‍🤝‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-1F91D-200D-1F468-1F3FF", + "label": "woman and man holding hands: light skin tone, dark skin tone", + "order": 2989, + "unicode": "👩🏻‍🤝‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F91D-200D-1F468-1F3FB", + "label": "woman and man holding hands: medium-light skin tone, light skin tone", + "order": 2990, + "unicode": "👩🏼‍🤝‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F91D-200D-1F468-1F3FD", + "label": "woman and man holding hands: medium-light skin tone, medium skin tone", + "order": 2992, + "unicode": "👩🏼‍🤝‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F91D-200D-1F468-1F3FE", + "label": "woman and man holding hands: medium-light skin tone, medium-dark skin tone", + "order": 2993, + "unicode": "👩🏼‍🤝‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-1F91D-200D-1F468-1F3FF", + "label": "woman and man holding hands: medium-light skin tone, dark skin tone", + "order": 2994, + "unicode": "👩🏼‍🤝‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F91D-200D-1F468-1F3FB", + "label": "woman and man holding hands: medium skin tone, light skin tone", + "order": 2995, + "unicode": "👩🏽‍🤝‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F91D-200D-1F468-1F3FC", + "label": "woman and man holding hands: medium skin tone, medium-light skin tone", + "order": 2996, + "unicode": "👩🏽‍🤝‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F91D-200D-1F468-1F3FE", + "label": "woman and man holding hands: medium skin tone, medium-dark skin tone", + "order": 2998, + "unicode": "👩🏽‍🤝‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-1F91D-200D-1F468-1F3FF", + "label": "woman and man holding hands: medium skin tone, dark skin tone", + "order": 2999, + "unicode": "👩🏽‍🤝‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F91D-200D-1F468-1F3FB", + "label": "woman and man holding hands: medium-dark skin tone, light skin tone", + "order": 3000, + "unicode": "👩🏾‍🤝‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F91D-200D-1F468-1F3FC", + "label": "woman and man holding hands: medium-dark skin tone, medium-light skin tone", + "order": 3001, + "unicode": "👩🏾‍🤝‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F91D-200D-1F468-1F3FD", + "label": "woman and man holding hands: medium-dark skin tone, medium skin tone", + "order": 3002, + "unicode": "👩🏾‍🤝‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-1F91D-200D-1F468-1F3FF", + "label": "woman and man holding hands: medium-dark skin tone, dark skin tone", + "order": 3004, + "unicode": "👩🏾‍🤝‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F91D-200D-1F468-1F3FB", + "label": "woman and man holding hands: dark skin tone, light skin tone", + "order": 3005, + "unicode": "👩🏿‍🤝‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F91D-200D-1F468-1F3FC", + "label": "woman and man holding hands: dark skin tone, medium-light skin tone", + "order": 3006, + "unicode": "👩🏿‍🤝‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F91D-200D-1F468-1F3FD", + "label": "woman and man holding hands: dark skin tone, medium skin tone", + "order": 3007, + "unicode": "👩🏿‍🤝‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-1F91D-200D-1F468-1F3FE", + "label": "woman and man holding hands: dark skin tone, medium-dark skin tone", + "order": 3008, + "unicode": "👩🏿‍🤝‍👨🏾" + } + ] + }, + { + "group": 1, + "hexcode": "1F46C", + "label": "men holding hands", + "order": 3010, + "tags": [ + "bae", + "bestie", + "bff", + "boys", + "brothers", + "couple", + "dating", + "flirt", + "friends", + "hand", + "hold", + "men", + "twins" + ], + "unicode": "👬", + "skins": [ + { + "group": 1, + "hexcode": "1F46C-1F3FB", + "label": "men holding hands: light skin tone", + "order": 3011, + "unicode": "👬🏻" + }, + { + "group": 1, + "hexcode": "1F46C-1F3FC", + "label": "men holding hands: medium-light skin tone", + "order": 3017, + "unicode": "👬🏼" + }, + { + "group": 1, + "hexcode": "1F46C-1F3FD", + "label": "men holding hands: medium skin tone", + "order": 3023, + "unicode": "👬🏽" + }, + { + "group": 1, + "hexcode": "1F46C-1F3FE", + "label": "men holding hands: medium-dark skin tone", + "order": 3029, + "unicode": "👬🏾" + }, + { + "group": 1, + "hexcode": "1F46C-1F3FF", + "label": "men holding hands: dark skin tone", + "order": 3035, + "unicode": "👬🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F91D-200D-1F468-1F3FC", + "label": "men holding hands: light skin tone, medium-light skin tone", + "order": 3012, + "unicode": "👨🏻‍🤝‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F91D-200D-1F468-1F3FD", + "label": "men holding hands: light skin tone, medium skin tone", + "order": 3013, + "unicode": "👨🏻‍🤝‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F91D-200D-1F468-1F3FE", + "label": "men holding hands: light skin tone, medium-dark skin tone", + "order": 3014, + "unicode": "👨🏻‍🤝‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-1F91D-200D-1F468-1F3FF", + "label": "men holding hands: light skin tone, dark skin tone", + "order": 3015, + "unicode": "👨🏻‍🤝‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F91D-200D-1F468-1F3FB", + "label": "men holding hands: medium-light skin tone, light skin tone", + "order": 3016, + "unicode": "👨🏼‍🤝‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F91D-200D-1F468-1F3FD", + "label": "men holding hands: medium-light skin tone, medium skin tone", + "order": 3018, + "unicode": "👨🏼‍🤝‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F91D-200D-1F468-1F3FE", + "label": "men holding hands: medium-light skin tone, medium-dark skin tone", + "order": 3019, + "unicode": "👨🏼‍🤝‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-1F91D-200D-1F468-1F3FF", + "label": "men holding hands: medium-light skin tone, dark skin tone", + "order": 3020, + "unicode": "👨🏼‍🤝‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F91D-200D-1F468-1F3FB", + "label": "men holding hands: medium skin tone, light skin tone", + "order": 3021, + "unicode": "👨🏽‍🤝‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F91D-200D-1F468-1F3FC", + "label": "men holding hands: medium skin tone, medium-light skin tone", + "order": 3022, + "unicode": "👨🏽‍🤝‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F91D-200D-1F468-1F3FE", + "label": "men holding hands: medium skin tone, medium-dark skin tone", + "order": 3024, + "unicode": "👨🏽‍🤝‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-1F91D-200D-1F468-1F3FF", + "label": "men holding hands: medium skin tone, dark skin tone", + "order": 3025, + "unicode": "👨🏽‍🤝‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F91D-200D-1F468-1F3FB", + "label": "men holding hands: medium-dark skin tone, light skin tone", + "order": 3026, + "unicode": "👨🏾‍🤝‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F91D-200D-1F468-1F3FC", + "label": "men holding hands: medium-dark skin tone, medium-light skin tone", + "order": 3027, + "unicode": "👨🏾‍🤝‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F91D-200D-1F468-1F3FD", + "label": "men holding hands: medium-dark skin tone, medium skin tone", + "order": 3028, + "unicode": "👨🏾‍🤝‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-1F91D-200D-1F468-1F3FF", + "label": "men holding hands: medium-dark skin tone, dark skin tone", + "order": 3030, + "unicode": "👨🏾‍🤝‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F91D-200D-1F468-1F3FB", + "label": "men holding hands: dark skin tone, light skin tone", + "order": 3031, + "unicode": "👨🏿‍🤝‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F91D-200D-1F468-1F3FC", + "label": "men holding hands: dark skin tone, medium-light skin tone", + "order": 3032, + "unicode": "👨🏿‍🤝‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F91D-200D-1F468-1F3FD", + "label": "men holding hands: dark skin tone, medium skin tone", + "order": 3033, + "unicode": "👨🏿‍🤝‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-1F91D-200D-1F468-1F3FE", + "label": "men holding hands: dark skin tone, medium-dark skin tone", + "order": 3034, + "unicode": "👨🏿‍🤝‍👨🏾" + } + ] + }, + { + "group": 1, + "hexcode": "1F48F", + "label": "kiss", + "order": 3036, + "tags": [ + "anniversary", + "babe", + "bae", + "couple", + "date", + "dating", + "heart", + "love", + "mwah", + "person", + "romance", + "together", + "xoxo" + ], + "unicode": "💏", + "skins": [ + { + "group": 1, + "hexcode": "1F48F-1F3FB", + "label": "kiss: light skin tone", + "order": 3037, + "unicode": "💏🏻" + }, + { + "group": 1, + "hexcode": "1F48F-1F3FC", + "label": "kiss: medium-light skin tone", + "order": 3038, + "unicode": "💏🏼" + }, + { + "group": 1, + "hexcode": "1F48F-1F3FD", + "label": "kiss: medium skin tone", + "order": 3039, + "unicode": "💏🏽" + }, + { + "group": 1, + "hexcode": "1F48F-1F3FE", + "label": "kiss: medium-dark skin tone", + "order": 3040, + "unicode": "💏🏾" + }, + { + "group": 1, + "hexcode": "1F48F-1F3FF", + "label": "kiss: dark skin tone", + "order": 3041, + "unicode": "💏🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FC", + "label": "kiss: person, person, light skin tone, medium-light skin tone", + "order": 3042, + "unicode": "🧑🏻‍❤️‍💋‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FD", + "label": "kiss: person, person, light skin tone, medium skin tone", + "order": 3044, + "unicode": "🧑🏻‍❤️‍💋‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FE", + "label": "kiss: person, person, light skin tone, medium-dark skin tone", + "order": 3046, + "unicode": "🧑🏻‍❤️‍💋‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FF", + "label": "kiss: person, person, light skin tone, dark skin tone", + "order": 3048, + "unicode": "🧑🏻‍❤️‍💋‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FB", + "label": "kiss: person, person, medium-light skin tone, light skin tone", + "order": 3050, + "unicode": "🧑🏼‍❤️‍💋‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FD", + "label": "kiss: person, person, medium-light skin tone, medium skin tone", + "order": 3052, + "unicode": "🧑🏼‍❤️‍💋‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FE", + "label": "kiss: person, person, medium-light skin tone, medium-dark skin tone", + "order": 3054, + "unicode": "🧑🏼‍❤️‍💋‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FF", + "label": "kiss: person, person, medium-light skin tone, dark skin tone", + "order": 3056, + "unicode": "🧑🏼‍❤️‍💋‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FB", + "label": "kiss: person, person, medium skin tone, light skin tone", + "order": 3058, + "unicode": "🧑🏽‍❤️‍💋‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FC", + "label": "kiss: person, person, medium skin tone, medium-light skin tone", + "order": 3060, + "unicode": "🧑🏽‍❤️‍💋‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FE", + "label": "kiss: person, person, medium skin tone, medium-dark skin tone", + "order": 3062, + "unicode": "🧑🏽‍❤️‍💋‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FF", + "label": "kiss: person, person, medium skin tone, dark skin tone", + "order": 3064, + "unicode": "🧑🏽‍❤️‍💋‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FB", + "label": "kiss: person, person, medium-dark skin tone, light skin tone", + "order": 3066, + "unicode": "🧑🏾‍❤️‍💋‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FC", + "label": "kiss: person, person, medium-dark skin tone, medium-light skin tone", + "order": 3068, + "unicode": "🧑🏾‍❤️‍💋‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FD", + "label": "kiss: person, person, medium-dark skin tone, medium skin tone", + "order": 3070, + "unicode": "🧑🏾‍❤️‍💋‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FF", + "label": "kiss: person, person, medium-dark skin tone, dark skin tone", + "order": 3072, + "unicode": "🧑🏾‍❤️‍💋‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FB", + "label": "kiss: person, person, dark skin tone, light skin tone", + "order": 3074, + "unicode": "🧑🏿‍❤️‍💋‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FC", + "label": "kiss: person, person, dark skin tone, medium-light skin tone", + "order": 3076, + "unicode": "🧑🏿‍❤️‍💋‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FD", + "label": "kiss: person, person, dark skin tone, medium skin tone", + "order": 3078, + "unicode": "🧑🏿‍❤️‍💋‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F9D1-1F3FE", + "label": "kiss: person, person, dark skin tone, medium-dark skin tone", + "order": 3080, + "unicode": "🧑🏿‍❤️‍💋‍🧑🏾" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-2764-FE0F-200D-1F48B-200D-1F468", + "label": "kiss: woman, man", + "order": 3082, + "tags": [ + "anniversary", + "babe", + "bae", + "couple", + "date", + "dating", + "heart", + "kiss", + "love", + "man", + "mwah", + "person", + "romance", + "together", + "woman", + "xoxo" + ], + "unicode": "👩‍❤️‍💋‍👨", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: woman, man, light skin tone", + "order": 3084, + "unicode": "👩🏻‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: woman, man, light skin tone, medium-light skin tone", + "order": 3086, + "unicode": "👩🏻‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: woman, man, light skin tone, medium skin tone", + "order": 3088, + "unicode": "👩🏻‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: woman, man, light skin tone, medium-dark skin tone", + "order": 3090, + "unicode": "👩🏻‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: woman, man, light skin tone, dark skin tone", + "order": 3092, + "unicode": "👩🏻‍❤️‍💋‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: woman, man, medium-light skin tone, light skin tone", + "order": 3094, + "unicode": "👩🏼‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: woman, man, medium-light skin tone", + "order": 3096, + "unicode": "👩🏼‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: woman, man, medium-light skin tone, medium skin tone", + "order": 3098, + "unicode": "👩🏼‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: woman, man, medium-light skin tone, medium-dark skin tone", + "order": 3100, + "unicode": "👩🏼‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: woman, man, medium-light skin tone, dark skin tone", + "order": 3102, + "unicode": "👩🏼‍❤️‍💋‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: woman, man, medium skin tone, light skin tone", + "order": 3104, + "unicode": "👩🏽‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: woman, man, medium skin tone, medium-light skin tone", + "order": 3106, + "unicode": "👩🏽‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: woman, man, medium skin tone", + "order": 3108, + "unicode": "👩🏽‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: woman, man, medium skin tone, medium-dark skin tone", + "order": 3110, + "unicode": "👩🏽‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: woman, man, medium skin tone, dark skin tone", + "order": 3112, + "unicode": "👩🏽‍❤️‍💋‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: woman, man, medium-dark skin tone, light skin tone", + "order": 3114, + "unicode": "👩🏾‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: woman, man, medium-dark skin tone, medium-light skin tone", + "order": 3116, + "unicode": "👩🏾‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: woman, man, medium-dark skin tone, medium skin tone", + "order": 3118, + "unicode": "👩🏾‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: woman, man, medium-dark skin tone", + "order": 3120, + "unicode": "👩🏾‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: woman, man, medium-dark skin tone, dark skin tone", + "order": 3122, + "unicode": "👩🏾‍❤️‍💋‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: woman, man, dark skin tone, light skin tone", + "order": 3124, + "unicode": "👩🏿‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: woman, man, dark skin tone, medium-light skin tone", + "order": 3126, + "unicode": "👩🏿‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: woman, man, dark skin tone, medium skin tone", + "order": 3128, + "unicode": "👩🏿‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: woman, man, dark skin tone, medium-dark skin tone", + "order": 3130, + "unicode": "👩🏿‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: woman, man, dark skin tone", + "order": 3132, + "unicode": "👩🏿‍❤️‍💋‍👨🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-2764-FE0F-200D-1F48B-200D-1F468", + "label": "kiss: man, man", + "order": 3134, + "tags": [ + "anniversary", + "babe", + "bae", + "couple", + "date", + "dating", + "heart", + "kiss", + "love", + "man", + "mwah", + "person", + "romance", + "together", + "xoxo" + ], + "unicode": "👨‍❤️‍💋‍👨", + "skins": [ + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: man, man, light skin tone", + "order": 3136, + "unicode": "👨🏻‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: man, man, light skin tone, medium-light skin tone", + "order": 3138, + "unicode": "👨🏻‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: man, man, light skin tone, medium skin tone", + "order": 3140, + "unicode": "👨🏻‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: man, man, light skin tone, medium-dark skin tone", + "order": 3142, + "unicode": "👨🏻‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: man, man, light skin tone, dark skin tone", + "order": 3144, + "unicode": "👨🏻‍❤️‍💋‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: man, man, medium-light skin tone, light skin tone", + "order": 3146, + "unicode": "👨🏼‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: man, man, medium-light skin tone", + "order": 3148, + "unicode": "👨🏼‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: man, man, medium-light skin tone, medium skin tone", + "order": 3150, + "unicode": "👨🏼‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: man, man, medium-light skin tone, medium-dark skin tone", + "order": 3152, + "unicode": "👨🏼‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: man, man, medium-light skin tone, dark skin tone", + "order": 3154, + "unicode": "👨🏼‍❤️‍💋‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: man, man, medium skin tone, light skin tone", + "order": 3156, + "unicode": "👨🏽‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: man, man, medium skin tone, medium-light skin tone", + "order": 3158, + "unicode": "👨🏽‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: man, man, medium skin tone", + "order": 3160, + "unicode": "👨🏽‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: man, man, medium skin tone, medium-dark skin tone", + "order": 3162, + "unicode": "👨🏽‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: man, man, medium skin tone, dark skin tone", + "order": 3164, + "unicode": "👨🏽‍❤️‍💋‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: man, man, medium-dark skin tone, light skin tone", + "order": 3166, + "unicode": "👨🏾‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: man, man, medium-dark skin tone, medium-light skin tone", + "order": 3168, + "unicode": "👨🏾‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: man, man, medium-dark skin tone, medium skin tone", + "order": 3170, + "unicode": "👨🏾‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: man, man, medium-dark skin tone", + "order": 3172, + "unicode": "👨🏾‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: man, man, medium-dark skin tone, dark skin tone", + "order": 3174, + "unicode": "👨🏾‍❤️‍💋‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FB", + "label": "kiss: man, man, dark skin tone, light skin tone", + "order": 3176, + "unicode": "👨🏿‍❤️‍💋‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FC", + "label": "kiss: man, man, dark skin tone, medium-light skin tone", + "order": 3178, + "unicode": "👨🏿‍❤️‍💋‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FD", + "label": "kiss: man, man, dark skin tone, medium skin tone", + "order": 3180, + "unicode": "👨🏿‍❤️‍💋‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FE", + "label": "kiss: man, man, dark skin tone, medium-dark skin tone", + "order": 3182, + "unicode": "👨🏿‍❤️‍💋‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F468-1F3FF", + "label": "kiss: man, man, dark skin tone", + "order": 3184, + "unicode": "👨🏿‍❤️‍💋‍👨🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-2764-FE0F-200D-1F48B-200D-1F469", + "label": "kiss: woman, woman", + "order": 3186, + "tags": [ + "anniversary", + "babe", + "bae", + "couple", + "date", + "dating", + "heart", + "kiss", + "love", + "mwah", + "person", + "romance", + "together", + "woman", + "xoxo" + ], + "unicode": "👩‍❤️‍💋‍👩", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FB", + "label": "kiss: woman, woman, light skin tone", + "order": 3188, + "unicode": "👩🏻‍❤️‍💋‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FC", + "label": "kiss: woman, woman, light skin tone, medium-light skin tone", + "order": 3190, + "unicode": "👩🏻‍❤️‍💋‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FD", + "label": "kiss: woman, woman, light skin tone, medium skin tone", + "order": 3192, + "unicode": "👩🏻‍❤️‍💋‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FE", + "label": "kiss: woman, woman, light skin tone, medium-dark skin tone", + "order": 3194, + "unicode": "👩🏻‍❤️‍💋‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FF", + "label": "kiss: woman, woman, light skin tone, dark skin tone", + "order": 3196, + "unicode": "👩🏻‍❤️‍💋‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FB", + "label": "kiss: woman, woman, medium-light skin tone, light skin tone", + "order": 3198, + "unicode": "👩🏼‍❤️‍💋‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FC", + "label": "kiss: woman, woman, medium-light skin tone", + "order": 3200, + "unicode": "👩🏼‍❤️‍💋‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FD", + "label": "kiss: woman, woman, medium-light skin tone, medium skin tone", + "order": 3202, + "unicode": "👩🏼‍❤️‍💋‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FE", + "label": "kiss: woman, woman, medium-light skin tone, medium-dark skin tone", + "order": 3204, + "unicode": "👩🏼‍❤️‍💋‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FF", + "label": "kiss: woman, woman, medium-light skin tone, dark skin tone", + "order": 3206, + "unicode": "👩🏼‍❤️‍💋‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FB", + "label": "kiss: woman, woman, medium skin tone, light skin tone", + "order": 3208, + "unicode": "👩🏽‍❤️‍💋‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FC", + "label": "kiss: woman, woman, medium skin tone, medium-light skin tone", + "order": 3210, + "unicode": "👩🏽‍❤️‍💋‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FD", + "label": "kiss: woman, woman, medium skin tone", + "order": 3212, + "unicode": "👩🏽‍❤️‍💋‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FE", + "label": "kiss: woman, woman, medium skin tone, medium-dark skin tone", + "order": 3214, + "unicode": "👩🏽‍❤️‍💋‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FF", + "label": "kiss: woman, woman, medium skin tone, dark skin tone", + "order": 3216, + "unicode": "👩🏽‍❤️‍💋‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FB", + "label": "kiss: woman, woman, medium-dark skin tone, light skin tone", + "order": 3218, + "unicode": "👩🏾‍❤️‍💋‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FC", + "label": "kiss: woman, woman, medium-dark skin tone, medium-light skin tone", + "order": 3220, + "unicode": "👩🏾‍❤️‍💋‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FD", + "label": "kiss: woman, woman, medium-dark skin tone, medium skin tone", + "order": 3222, + "unicode": "👩🏾‍❤️‍💋‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FE", + "label": "kiss: woman, woman, medium-dark skin tone", + "order": 3224, + "unicode": "👩🏾‍❤️‍💋‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FF", + "label": "kiss: woman, woman, medium-dark skin tone, dark skin tone", + "order": 3226, + "unicode": "👩🏾‍❤️‍💋‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FB", + "label": "kiss: woman, woman, dark skin tone, light skin tone", + "order": 3228, + "unicode": "👩🏿‍❤️‍💋‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FC", + "label": "kiss: woman, woman, dark skin tone, medium-light skin tone", + "order": 3230, + "unicode": "👩🏿‍❤️‍💋‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FD", + "label": "kiss: woman, woman, dark skin tone, medium skin tone", + "order": 3232, + "unicode": "👩🏿‍❤️‍💋‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FE", + "label": "kiss: woman, woman, dark skin tone, medium-dark skin tone", + "order": 3234, + "unicode": "👩🏿‍❤️‍💋‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F48B-200D-1F469-1F3FF", + "label": "kiss: woman, woman, dark skin tone", + "order": 3236, + "unicode": "👩🏿‍❤️‍💋‍👩🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F491", + "label": "couple with heart", + "order": 3238, + "tags": [ + "anniversary", + "babe", + "bae", + "couple", + "dating", + "heart", + "kiss", + "love", + "person", + "relationship", + "romance", + "together", + "you" + ], + "unicode": "💑", + "skins": [ + { + "group": 1, + "hexcode": "1F491-1F3FB", + "label": "couple with heart: light skin tone", + "order": 3239, + "unicode": "💑🏻" + }, + { + "group": 1, + "hexcode": "1F491-1F3FC", + "label": "couple with heart: medium-light skin tone", + "order": 3240, + "unicode": "💑🏼" + }, + { + "group": 1, + "hexcode": "1F491-1F3FD", + "label": "couple with heart: medium skin tone", + "order": 3241, + "unicode": "💑🏽" + }, + { + "group": 1, + "hexcode": "1F491-1F3FE", + "label": "couple with heart: medium-dark skin tone", + "order": 3242, + "unicode": "💑🏾" + }, + { + "group": 1, + "hexcode": "1F491-1F3FF", + "label": "couple with heart: dark skin tone", + "order": 3243, + "unicode": "💑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-2764-FE0F-200D-1F9D1-1F3FC", + "label": "couple with heart: person, person, light skin tone, medium-light skin tone", + "order": 3244, + "unicode": "🧑🏻‍❤️‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-2764-FE0F-200D-1F9D1-1F3FD", + "label": "couple with heart: person, person, light skin tone, medium skin tone", + "order": 3246, + "unicode": "🧑🏻‍❤️‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-2764-FE0F-200D-1F9D1-1F3FE", + "label": "couple with heart: person, person, light skin tone, medium-dark skin tone", + "order": 3248, + "unicode": "🧑🏻‍❤️‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FB-200D-2764-FE0F-200D-1F9D1-1F3FF", + "label": "couple with heart: person, person, light skin tone, dark skin tone", + "order": 3250, + "unicode": "🧑🏻‍❤️‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-2764-FE0F-200D-1F9D1-1F3FB", + "label": "couple with heart: person, person, medium-light skin tone, light skin tone", + "order": 3252, + "unicode": "🧑🏼‍❤️‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-2764-FE0F-200D-1F9D1-1F3FD", + "label": "couple with heart: person, person, medium-light skin tone, medium skin tone", + "order": 3254, + "unicode": "🧑🏼‍❤️‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-2764-FE0F-200D-1F9D1-1F3FE", + "label": "couple with heart: person, person, medium-light skin tone, medium-dark skin tone", + "order": 3256, + "unicode": "🧑🏼‍❤️‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FC-200D-2764-FE0F-200D-1F9D1-1F3FF", + "label": "couple with heart: person, person, medium-light skin tone, dark skin tone", + "order": 3258, + "unicode": "🧑🏼‍❤️‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-2764-FE0F-200D-1F9D1-1F3FB", + "label": "couple with heart: person, person, medium skin tone, light skin tone", + "order": 3260, + "unicode": "🧑🏽‍❤️‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-2764-FE0F-200D-1F9D1-1F3FC", + "label": "couple with heart: person, person, medium skin tone, medium-light skin tone", + "order": 3262, + "unicode": "🧑🏽‍❤️‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-2764-FE0F-200D-1F9D1-1F3FE", + "label": "couple with heart: person, person, medium skin tone, medium-dark skin tone", + "order": 3264, + "unicode": "🧑🏽‍❤️‍🧑🏾" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FD-200D-2764-FE0F-200D-1F9D1-1F3FF", + "label": "couple with heart: person, person, medium skin tone, dark skin tone", + "order": 3266, + "unicode": "🧑🏽‍❤️‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-2764-FE0F-200D-1F9D1-1F3FB", + "label": "couple with heart: person, person, medium-dark skin tone, light skin tone", + "order": 3268, + "unicode": "🧑🏾‍❤️‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-2764-FE0F-200D-1F9D1-1F3FC", + "label": "couple with heart: person, person, medium-dark skin tone, medium-light skin tone", + "order": 3270, + "unicode": "🧑🏾‍❤️‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-2764-FE0F-200D-1F9D1-1F3FD", + "label": "couple with heart: person, person, medium-dark skin tone, medium skin tone", + "order": 3272, + "unicode": "🧑🏾‍❤️‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FE-200D-2764-FE0F-200D-1F9D1-1F3FF", + "label": "couple with heart: person, person, medium-dark skin tone, dark skin tone", + "order": 3274, + "unicode": "🧑🏾‍❤️‍🧑🏿" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-2764-FE0F-200D-1F9D1-1F3FB", + "label": "couple with heart: person, person, dark skin tone, light skin tone", + "order": 3276, + "unicode": "🧑🏿‍❤️‍🧑🏻" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-2764-FE0F-200D-1F9D1-1F3FC", + "label": "couple with heart: person, person, dark skin tone, medium-light skin tone", + "order": 3278, + "unicode": "🧑🏿‍❤️‍🧑🏼" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-2764-FE0F-200D-1F9D1-1F3FD", + "label": "couple with heart: person, person, dark skin tone, medium skin tone", + "order": 3280, + "unicode": "🧑🏿‍❤️‍🧑🏽" + }, + { + "group": 1, + "hexcode": "1F9D1-1F3FF-200D-2764-FE0F-200D-1F9D1-1F3FE", + "label": "couple with heart: person, person, dark skin tone, medium-dark skin tone", + "order": 3282, + "unicode": "🧑🏿‍❤️‍🧑🏾" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-2764-FE0F-200D-1F468", + "label": "couple with heart: woman, man", + "order": 3284, + "tags": [ + "anniversary", + "babe", + "bae", + "couple", + "dating", + "heart", + "kiss", + "love", + "man", + "person", + "relationship", + "romance", + "together", + "woman", + "you" + ], + "unicode": "👩‍❤️‍👨", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: woman, man, light skin tone", + "order": 3286, + "unicode": "👩🏻‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: woman, man, light skin tone, medium-light skin tone", + "order": 3288, + "unicode": "👩🏻‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: woman, man, light skin tone, medium skin tone", + "order": 3290, + "unicode": "👩🏻‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: woman, man, light skin tone, medium-dark skin tone", + "order": 3292, + "unicode": "👩🏻‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: woman, man, light skin tone, dark skin tone", + "order": 3294, + "unicode": "👩🏻‍❤️‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: woman, man, medium-light skin tone, light skin tone", + "order": 3296, + "unicode": "👩🏼‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: woman, man, medium-light skin tone", + "order": 3298, + "unicode": "👩🏼‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: woman, man, medium-light skin tone, medium skin tone", + "order": 3300, + "unicode": "👩🏼‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: woman, man, medium-light skin tone, medium-dark skin tone", + "order": 3302, + "unicode": "👩🏼‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: woman, man, medium-light skin tone, dark skin tone", + "order": 3304, + "unicode": "👩🏼‍❤️‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: woman, man, medium skin tone, light skin tone", + "order": 3306, + "unicode": "👩🏽‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: woman, man, medium skin tone, medium-light skin tone", + "order": 3308, + "unicode": "👩🏽‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: woman, man, medium skin tone", + "order": 3310, + "unicode": "👩🏽‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: woman, man, medium skin tone, medium-dark skin tone", + "order": 3312, + "unicode": "👩🏽‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: woman, man, medium skin tone, dark skin tone", + "order": 3314, + "unicode": "👩🏽‍❤️‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: woman, man, medium-dark skin tone, light skin tone", + "order": 3316, + "unicode": "👩🏾‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: woman, man, medium-dark skin tone, medium-light skin tone", + "order": 3318, + "unicode": "👩🏾‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: woman, man, medium-dark skin tone, medium skin tone", + "order": 3320, + "unicode": "👩🏾‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: woman, man, medium-dark skin tone", + "order": 3322, + "unicode": "👩🏾‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: woman, man, medium-dark skin tone, dark skin tone", + "order": 3324, + "unicode": "👩🏾‍❤️‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: woman, man, dark skin tone, light skin tone", + "order": 3326, + "unicode": "👩🏿‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: woman, man, dark skin tone, medium-light skin tone", + "order": 3328, + "unicode": "👩🏿‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: woman, man, dark skin tone, medium skin tone", + "order": 3330, + "unicode": "👩🏿‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: woman, man, dark skin tone, medium-dark skin tone", + "order": 3332, + "unicode": "👩🏿‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: woman, man, dark skin tone", + "order": 3334, + "unicode": "👩🏿‍❤️‍👨🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-2764-FE0F-200D-1F468", + "label": "couple with heart: man, man", + "order": 3336, + "tags": [ + "anniversary", + "babe", + "bae", + "couple", + "dating", + "heart", + "kiss", + "love", + "man", + "person", + "relationship", + "romance", + "together", + "you" + ], + "unicode": "👨‍❤️‍👨", + "skins": [ + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: man, man, light skin tone", + "order": 3338, + "unicode": "👨🏻‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: man, man, light skin tone, medium-light skin tone", + "order": 3340, + "unicode": "👨🏻‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: man, man, light skin tone, medium skin tone", + "order": 3342, + "unicode": "👨🏻‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: man, man, light skin tone, medium-dark skin tone", + "order": 3344, + "unicode": "👨🏻‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FB-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: man, man, light skin tone, dark skin tone", + "order": 3346, + "unicode": "👨🏻‍❤️‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: man, man, medium-light skin tone, light skin tone", + "order": 3348, + "unicode": "👨🏼‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: man, man, medium-light skin tone", + "order": 3350, + "unicode": "👨🏼‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: man, man, medium-light skin tone, medium skin tone", + "order": 3352, + "unicode": "👨🏼‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: man, man, medium-light skin tone, medium-dark skin tone", + "order": 3354, + "unicode": "👨🏼‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FC-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: man, man, medium-light skin tone, dark skin tone", + "order": 3356, + "unicode": "👨🏼‍❤️‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: man, man, medium skin tone, light skin tone", + "order": 3358, + "unicode": "👨🏽‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: man, man, medium skin tone, medium-light skin tone", + "order": 3360, + "unicode": "👨🏽‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: man, man, medium skin tone", + "order": 3362, + "unicode": "👨🏽‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: man, man, medium skin tone, medium-dark skin tone", + "order": 3364, + "unicode": "👨🏽‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FD-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: man, man, medium skin tone, dark skin tone", + "order": 3366, + "unicode": "👨🏽‍❤️‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: man, man, medium-dark skin tone, light skin tone", + "order": 3368, + "unicode": "👨🏾‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: man, man, medium-dark skin tone, medium-light skin tone", + "order": 3370, + "unicode": "👨🏾‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: man, man, medium-dark skin tone, medium skin tone", + "order": 3372, + "unicode": "👨🏾‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: man, man, medium-dark skin tone", + "order": 3374, + "unicode": "👨🏾‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FE-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: man, man, medium-dark skin tone, dark skin tone", + "order": 3376, + "unicode": "👨🏾‍❤️‍👨🏿" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F468-1F3FB", + "label": "couple with heart: man, man, dark skin tone, light skin tone", + "order": 3378, + "unicode": "👨🏿‍❤️‍👨🏻" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F468-1F3FC", + "label": "couple with heart: man, man, dark skin tone, medium-light skin tone", + "order": 3380, + "unicode": "👨🏿‍❤️‍👨🏼" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F468-1F3FD", + "label": "couple with heart: man, man, dark skin tone, medium skin tone", + "order": 3382, + "unicode": "👨🏿‍❤️‍👨🏽" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F468-1F3FE", + "label": "couple with heart: man, man, dark skin tone, medium-dark skin tone", + "order": 3384, + "unicode": "👨🏿‍❤️‍👨🏾" + }, + { + "group": 1, + "hexcode": "1F468-1F3FF-200D-2764-FE0F-200D-1F468-1F3FF", + "label": "couple with heart: man, man, dark skin tone", + "order": 3386, + "unicode": "👨🏿‍❤️‍👨🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F469-200D-2764-FE0F-200D-1F469", + "label": "couple with heart: woman, woman", + "order": 3388, + "tags": [ + "anniversary", + "babe", + "bae", + "couple", + "dating", + "heart", + "kiss", + "love", + "person", + "relationship", + "romance", + "together", + "woman", + "you" + ], + "unicode": "👩‍❤️‍👩", + "skins": [ + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F469-1F3FB", + "label": "couple with heart: woman, woman, light skin tone", + "order": 3390, + "unicode": "👩🏻‍❤️‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F469-1F3FC", + "label": "couple with heart: woman, woman, light skin tone, medium-light skin tone", + "order": 3392, + "unicode": "👩🏻‍❤️‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F469-1F3FD", + "label": "couple with heart: woman, woman, light skin tone, medium skin tone", + "order": 3394, + "unicode": "👩🏻‍❤️‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F469-1F3FE", + "label": "couple with heart: woman, woman, light skin tone, medium-dark skin tone", + "order": 3396, + "unicode": "👩🏻‍❤️‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FB-200D-2764-FE0F-200D-1F469-1F3FF", + "label": "couple with heart: woman, woman, light skin tone, dark skin tone", + "order": 3398, + "unicode": "👩🏻‍❤️‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F469-1F3FB", + "label": "couple with heart: woman, woman, medium-light skin tone, light skin tone", + "order": 3400, + "unicode": "👩🏼‍❤️‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F469-1F3FC", + "label": "couple with heart: woman, woman, medium-light skin tone", + "order": 3402, + "unicode": "👩🏼‍❤️‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F469-1F3FD", + "label": "couple with heart: woman, woman, medium-light skin tone, medium skin tone", + "order": 3404, + "unicode": "👩🏼‍❤️‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F469-1F3FE", + "label": "couple with heart: woman, woman, medium-light skin tone, medium-dark skin tone", + "order": 3406, + "unicode": "👩🏼‍❤️‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FC-200D-2764-FE0F-200D-1F469-1F3FF", + "label": "couple with heart: woman, woman, medium-light skin tone, dark skin tone", + "order": 3408, + "unicode": "👩🏼‍❤️‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F469-1F3FB", + "label": "couple with heart: woman, woman, medium skin tone, light skin tone", + "order": 3410, + "unicode": "👩🏽‍❤️‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F469-1F3FC", + "label": "couple with heart: woman, woman, medium skin tone, medium-light skin tone", + "order": 3412, + "unicode": "👩🏽‍❤️‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F469-1F3FD", + "label": "couple with heart: woman, woman, medium skin tone", + "order": 3414, + "unicode": "👩🏽‍❤️‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F469-1F3FE", + "label": "couple with heart: woman, woman, medium skin tone, medium-dark skin tone", + "order": 3416, + "unicode": "👩🏽‍❤️‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FD-200D-2764-FE0F-200D-1F469-1F3FF", + "label": "couple with heart: woman, woman, medium skin tone, dark skin tone", + "order": 3418, + "unicode": "👩🏽‍❤️‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F469-1F3FB", + "label": "couple with heart: woman, woman, medium-dark skin tone, light skin tone", + "order": 3420, + "unicode": "👩🏾‍❤️‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F469-1F3FC", + "label": "couple with heart: woman, woman, medium-dark skin tone, medium-light skin tone", + "order": 3422, + "unicode": "👩🏾‍❤️‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F469-1F3FD", + "label": "couple with heart: woman, woman, medium-dark skin tone, medium skin tone", + "order": 3424, + "unicode": "👩🏾‍❤️‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F469-1F3FE", + "label": "couple with heart: woman, woman, medium-dark skin tone", + "order": 3426, + "unicode": "👩🏾‍❤️‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FE-200D-2764-FE0F-200D-1F469-1F3FF", + "label": "couple with heart: woman, woman, medium-dark skin tone, dark skin tone", + "order": 3428, + "unicode": "👩🏾‍❤️‍👩🏿" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F469-1F3FB", + "label": "couple with heart: woman, woman, dark skin tone, light skin tone", + "order": 3430, + "unicode": "👩🏿‍❤️‍👩🏻" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F469-1F3FC", + "label": "couple with heart: woman, woman, dark skin tone, medium-light skin tone", + "order": 3432, + "unicode": "👩🏿‍❤️‍👩🏼" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F469-1F3FD", + "label": "couple with heart: woman, woman, dark skin tone, medium skin tone", + "order": 3434, + "unicode": "👩🏿‍❤️‍👩🏽" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F469-1F3FE", + "label": "couple with heart: woman, woman, dark skin tone, medium-dark skin tone", + "order": 3436, + "unicode": "👩🏿‍❤️‍👩🏾" + }, + { + "group": 1, + "hexcode": "1F469-1F3FF-200D-2764-FE0F-200D-1F469-1F3FF", + "label": "couple with heart: woman, woman, dark skin tone", + "order": 3438, + "unicode": "👩🏿‍❤️‍👩🏿" + } + ] + }, + { + "group": 1, + "hexcode": "1F468-200D-1F469-200D-1F466", + "label": "family: man, woman, boy", + "order": 3440, + "tags": ["boy", "child", "family", "man", "woman"], + "unicode": "👨‍👩‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F469-200D-1F467", + "label": "family: man, woman, girl", + "order": 3441, + "tags": ["child", "family", "girl", "man", "woman"], + "unicode": "👨‍👩‍👧" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F469-200D-1F467-200D-1F466", + "label": "family: man, woman, girl, boy", + "order": 3442, + "tags": ["boy", "child", "family", "girl", "man", "woman"], + "unicode": "👨‍👩‍👧‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F469-200D-1F466-200D-1F466", + "label": "family: man, woman, boy, boy", + "order": 3443, + "tags": ["boy", "child", "family", "man", "woman"], + "unicode": "👨‍👩‍👦‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F469-200D-1F467-200D-1F467", + "label": "family: man, woman, girl, girl", + "order": 3444, + "tags": ["child", "family", "girl", "man", "woman"], + "unicode": "👨‍👩‍👧‍👧" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F468-200D-1F466", + "label": "family: man, man, boy", + "order": 3445, + "tags": ["boy", "child", "family", "man"], + "unicode": "👨‍👨‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F468-200D-1F467", + "label": "family: man, man, girl", + "order": 3446, + "tags": ["child", "family", "girl", "man"], + "unicode": "👨‍👨‍👧" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F468-200D-1F467-200D-1F466", + "label": "family: man, man, girl, boy", + "order": 3447, + "tags": ["boy", "child", "family", "girl", "man"], + "unicode": "👨‍👨‍👧‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F468-200D-1F466-200D-1F466", + "label": "family: man, man, boy, boy", + "order": 3448, + "tags": ["boy", "child", "family", "man"], + "unicode": "👨‍👨‍👦‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F468-200D-1F467-200D-1F467", + "label": "family: man, man, girl, girl", + "order": 3449, + "tags": ["child", "family", "girl", "man"], + "unicode": "👨‍👨‍👧‍👧" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F469-200D-1F466", + "label": "family: woman, woman, boy", + "order": 3450, + "tags": ["boy", "child", "family", "woman"], + "unicode": "👩‍👩‍👦" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F469-200D-1F467", + "label": "family: woman, woman, girl", + "order": 3451, + "tags": ["child", "family", "girl", "woman"], + "unicode": "👩‍👩‍👧" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F469-200D-1F467-200D-1F466", + "label": "family: woman, woman, girl, boy", + "order": 3452, + "tags": ["boy", "child", "family", "girl", "woman"], + "unicode": "👩‍👩‍👧‍👦" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F469-200D-1F466-200D-1F466", + "label": "family: woman, woman, boy, boy", + "order": 3453, + "tags": ["boy", "child", "family", "woman"], + "unicode": "👩‍👩‍👦‍👦" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F469-200D-1F467-200D-1F467", + "label": "family: woman, woman, girl, girl", + "order": 3454, + "tags": ["child", "family", "girl", "woman"], + "unicode": "👩‍👩‍👧‍👧" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F466", + "label": "family: man, boy", + "order": 3455, + "tags": ["boy", "child", "family", "man"], + "unicode": "👨‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F466-200D-1F466", + "label": "family: man, boy, boy", + "order": 3456, + "tags": ["boy", "child", "family", "man"], + "unicode": "👨‍👦‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F467", + "label": "family: man, girl", + "order": 3457, + "tags": ["child", "family", "girl", "man"], + "unicode": "👨‍👧" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F467-200D-1F466", + "label": "family: man, girl, boy", + "order": 3458, + "tags": ["boy", "child", "family", "girl", "man"], + "unicode": "👨‍👧‍👦" + }, + { + "group": 1, + "hexcode": "1F468-200D-1F467-200D-1F467", + "label": "family: man, girl, girl", + "order": 3459, + "tags": ["child", "family", "girl", "man"], + "unicode": "👨‍👧‍👧" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F466", + "label": "family: woman, boy", + "order": 3460, + "tags": ["boy", "child", "family", "woman"], + "unicode": "👩‍👦" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F466-200D-1F466", + "label": "family: woman, boy, boy", + "order": 3461, + "tags": ["boy", "child", "family", "woman"], + "unicode": "👩‍👦‍👦" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F467", + "label": "family: woman, girl", + "order": 3462, + "tags": ["child", "family", "girl", "woman"], + "unicode": "👩‍👧" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F467-200D-1F466", + "label": "family: woman, girl, boy", + "order": 3463, + "tags": ["boy", "child", "family", "girl", "woman"], + "unicode": "👩‍👧‍👦" + }, + { + "group": 1, + "hexcode": "1F469-200D-1F467-200D-1F467", + "label": "family: woman, girl, girl", + "order": 3464, + "tags": ["child", "family", "girl", "woman"], + "unicode": "👩‍👧‍👧" + }, + { + "group": 1, + "hexcode": "1F5E3", + "label": "speaking head", + "order": 3466, + "tags": ["face", "head", "silhouette", "speak", "speaking"], + "unicode": "🗣️" + }, + { + "group": 1, + "hexcode": "1F464", + "label": "bust in silhouette", + "order": 3467, + "tags": ["bust", "mysterious", "shadow", "silhouette"], + "unicode": "👤" + }, + { + "group": 1, + "hexcode": "1F465", + "label": "busts in silhouette", + "order": 3468, + "tags": [ + "bff", + "bust", + "busts", + "everyone", + "friend", + "friends", + "people", + "silhouette" + ], + "unicode": "👥" + }, + { + "group": 1, + "hexcode": "1FAC2", + "label": "people hugging", + "order": 3469, + "tags": [ + "comfort", + "embrace", + "farewell", + "friendship", + "goodbye", + "hello", + "hug", + "hugging", + "love", + "people", + "thanks" + ], + "unicode": "🫂" + }, + { + "group": 1, + "hexcode": "1F46A", + "label": "family", + "order": 3470, + "tags": ["child"], + "unicode": "👪️" + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9D1-200D-1F9D2", + "label": "family: adult, adult, child", + "order": 3471, + "tags": ["adult", "child", "family"], + "unicode": "🧑‍🧑‍🧒" + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9D1-200D-1F9D2-200D-1F9D2", + "label": "family: adult, adult, child, child", + "order": 3472, + "tags": ["adult", "child", "family"], + "unicode": "🧑‍🧑‍🧒‍🧒" + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9D2", + "label": "family: adult, child", + "order": 3473, + "tags": ["adult", "child", "family"], + "unicode": "🧑‍🧒" + }, + { + "group": 1, + "hexcode": "1F9D1-200D-1F9D2-200D-1F9D2", + "label": "family: adult, child, child", + "order": 3474, + "tags": ["adult", "child", "family"], + "unicode": "🧑‍🧒‍🧒" + }, + { + "group": 1, + "hexcode": "1F463", + "label": "footprints", + "order": 3475, + "tags": ["barefoot", "clothing", "footprint", "omw", "print", "walk"], + "unicode": "👣" + }, + { + "group": 1, + "hexcode": "1FAC6", + "label": "fingerprint", + "order": 3476, + "tags": [ + "clue", + "crime", + "detective", + "forensics", + "identity", + "mystery", + "print", + "safety", + "trace" + ], + "unicode": "🫆" + } + ] + }, + { + "name": "Animals & Nature", + "emojis": [ + { + "group": 3, + "hexcode": "1F435", + "label": "monkey face", + "order": 3486, + "tags": ["animal", "banana", "face", "monkey"], + "unicode": "🐵" + }, + { + "group": 3, + "hexcode": "1F412", + "label": "monkey", + "order": 3487, + "tags": ["animal", "banana"], + "unicode": "🐒" + }, + { + "group": 3, + "hexcode": "1F98D", + "label": "gorilla", + "order": 3488, + "tags": ["animal"], + "unicode": "🦍" + }, + { + "group": 3, + "hexcode": "1F9A7", + "label": "orangutan", + "order": 3489, + "tags": ["animal", "ape", "monkey"], + "unicode": "🦧" + }, + { + "group": 3, + "hexcode": "1F436", + "label": "dog face", + "order": 3490, + "tags": ["adorbs", "animal", "dog", "face", "pet", "puppies", "puppy"], + "unicode": "🐶" + }, + { + "group": 3, + "hexcode": "1F415", + "label": "dog", + "order": 3491, + "tags": ["animal", "animals", "dogs", "pet"], + "unicode": "🐕️" + }, + { + "group": 3, + "hexcode": "1F9AE", + "label": "guide dog", + "order": 3492, + "tags": ["accessibility", "animal", "blind", "dog", "guide"], + "unicode": "🦮" + }, + { + "group": 3, + "hexcode": "1F415-200D-1F9BA", + "label": "service dog", + "order": 3493, + "tags": ["accessibility", "animal", "assistance", "dog", "service"], + "unicode": "🐕‍🦺" + }, + { + "group": 3, + "hexcode": "1F429", + "label": "poodle", + "order": 3494, + "tags": ["animal", "dog", "fluffy"], + "unicode": "🐩" + }, + { + "group": 3, + "hexcode": "1F43A", + "label": "wolf", + "order": 3495, + "tags": ["animal", "face"], + "unicode": "🐺" + }, + { + "group": 3, + "hexcode": "1F98A", + "label": "fox", + "order": 3496, + "tags": ["animal", "face"], + "unicode": "🦊" + }, + { + "group": 3, + "hexcode": "1F99D", + "label": "raccoon", + "order": 3497, + "tags": ["animal", "curious", "sly"], + "unicode": "🦝" + }, + { + "group": 3, + "hexcode": "1F431", + "label": "cat face", + "order": 3498, + "tags": ["animal", "cat", "face", "kitten", "kitty", "pet"], + "unicode": "🐱" + }, + { + "group": 3, + "hexcode": "1F408", + "label": "cat", + "order": 3499, + "tags": ["animal", "animals", "cats", "kitten", "pet"], + "unicode": "🐈️" + }, + { + "group": 3, + "hexcode": "1F408-200D-2B1B", + "label": "black cat", + "order": 3500, + "tags": [ + "animal", + "black", + "cat", + "feline", + "halloween", + "meow", + "unlucky" + ], + "unicode": "🐈‍⬛" + }, + { + "group": 3, + "hexcode": "1F981", + "label": "lion", + "order": 3501, + "tags": [ + "alpha", + "animal", + "face", + "leo", + "mane", + "order", + "rawr", + "roar", + "safari", + "strong", + "zodiac" + ], + "unicode": "🦁" + }, + { + "group": 3, + "hexcode": "1F42F", + "label": "tiger face", + "order": 3502, + "tags": ["animal", "big", "cat", "face", "predator", "tiger"], + "unicode": "🐯" + }, + { + "group": 3, + "hexcode": "1F405", + "label": "tiger", + "order": 3503, + "tags": ["animal", "big", "cat", "predator", "zoo"], + "unicode": "🐅" + }, + { + "group": 3, + "hexcode": "1F406", + "label": "leopard", + "order": 3504, + "tags": ["animal", "big", "cat", "predator", "zoo"], + "unicode": "🐆" + }, + { + "group": 3, + "hexcode": "1F434", + "label": "horse face", + "order": 3505, + "tags": [ + "animal", + "dressage", + "equine", + "face", + "farm", + "horse", + "horses" + ], + "unicode": "🐴" + }, + { + "group": 3, + "hexcode": "1FACE", + "label": "moose", + "order": 3506, + "tags": ["alces", "animal", "antlers", "elk", "mammal"], + "unicode": "🫎" + }, + { + "group": 3, + "hexcode": "1FACF", + "label": "donkey", + "order": 3507, + "tags": [ + "animal", + "ass", + "burro", + "hinny", + "mammal", + "mule", + "stubborn" + ], + "unicode": "🫏" + }, + { + "group": 3, + "hexcode": "1F40E", + "label": "horse", + "order": 3508, + "tags": ["animal", "equestrian", "farm", "racehorse", "racing"], + "unicode": "🐎" + }, + { + "group": 3, + "hexcode": "1F984", + "label": "unicorn", + "order": 3509, + "tags": ["face"], + "unicode": "🦄" + }, + { + "group": 3, + "hexcode": "1F993", + "label": "zebra", + "order": 3510, + "tags": ["animal", "stripe"], + "unicode": "🦓" + }, + { + "group": 3, + "hexcode": "1F98C", + "label": "deer", + "order": 3511, + "tags": ["animal"], + "unicode": "🦌" + }, + { + "group": 3, + "hexcode": "1F9AC", + "label": "bison", + "order": 3512, + "tags": ["animal", "buffalo", "herd", "wisent"], + "unicode": "🦬" + }, + { + "group": 3, + "hexcode": "1F42E", + "label": "cow face", + "order": 3513, + "tags": ["animal", "cow", "face", "farm", "milk", "moo"], + "unicode": "🐮" + }, + { + "group": 3, + "hexcode": "1F402", + "label": "ox", + "order": 3514, + "tags": ["animal", "animals", "bull", "farm", "taurus", "zodiac"], + "unicode": "🐂" + }, + { + "group": 3, + "hexcode": "1F403", + "label": "water buffalo", + "order": 3515, + "tags": ["animal", "buffalo", "water", "zoo"], + "unicode": "🐃" + }, + { + "group": 3, + "hexcode": "1F404", + "label": "cow", + "order": 3516, + "tags": ["animal", "animals", "farm", "milk", "moo"], + "unicode": "🐄" + }, + { + "group": 3, + "hexcode": "1F437", + "label": "pig face", + "order": 3517, + "tags": ["animal", "bacon", "face", "farm", "pig", "pork"], + "unicode": "🐷" + }, + { + "group": 3, + "hexcode": "1F416", + "label": "pig", + "order": 3518, + "tags": ["animal", "bacon", "farm", "pork", "sow"], + "unicode": "🐖" + }, + { + "group": 3, + "hexcode": "1F417", + "label": "boar", + "order": 3519, + "tags": ["animal", "pig"], + "unicode": "🐗" + }, + { + "group": 3, + "hexcode": "1F43D", + "label": "pig nose", + "order": 3520, + "tags": ["animal", "face", "farm", "nose", "pig", "smell", "snout"], + "unicode": "🐽" + }, + { + "group": 3, + "hexcode": "1F40F", + "label": "ram", + "order": 3521, + "tags": ["animal", "aries", "horns", "male", "sheep", "zodiac", "zoo"], + "unicode": "🐏" + }, + { + "group": 3, + "hexcode": "1F411", + "label": "ewe", + "order": 3522, + "tags": [ + "animal", + "baa", + "farm", + "female", + "fluffy", + "lamb", + "sheep", + "wool" + ], + "unicode": "🐑" + }, + { + "group": 3, + "hexcode": "1F410", + "label": "goat", + "order": 3523, + "tags": ["animal", "capricorn", "farm", "milk", "zodiac"], + "unicode": "🐐" + }, + { + "group": 3, + "hexcode": "1F42A", + "label": "camel", + "order": 3524, + "tags": ["animal", "desert", "dromedary", "hump", "one"], + "unicode": "🐪" + }, + { + "group": 3, + "hexcode": "1F42B", + "label": "two-hump camel", + "order": 3525, + "tags": [ + "animal", + "bactrian", + "camel", + "desert", + "hump", + "two", + "two-hump" + ], + "unicode": "🐫" + }, + { + "group": 3, + "hexcode": "1F999", + "label": "llama", + "order": 3526, + "tags": ["alpaca", "animal", "guanaco", "vicuña", "wool"], + "unicode": "🦙" + }, + { + "group": 3, + "hexcode": "1F992", + "label": "giraffe", + "order": 3527, + "tags": ["animal", "spots"], + "unicode": "🦒" + }, + { + "group": 3, + "hexcode": "1F418", + "label": "elephant", + "order": 3528, + "tags": ["animal"], + "unicode": "🐘" + }, + { + "group": 3, + "hexcode": "1F9A3", + "label": "mammoth", + "order": 3529, + "tags": ["animal", "extinction", "large", "tusk", "wooly"], + "unicode": "🦣" + }, + { + "group": 3, + "hexcode": "1F98F", + "label": "rhinoceros", + "order": 3530, + "tags": ["animal"], + "unicode": "🦏" + }, + { + "group": 3, + "hexcode": "1F99B", + "label": "hippopotamus", + "order": 3531, + "tags": ["animal", "hippo"], + "unicode": "🦛" + }, + { + "group": 3, + "hexcode": "1F42D", + "label": "mouse face", + "order": 3532, + "tags": ["animal", "face", "mouse"], + "unicode": "🐭" + }, + { + "group": 3, + "hexcode": "1F401", + "label": "mouse", + "order": 3533, + "tags": ["animal", "animals"], + "unicode": "🐁" + }, + { + "group": 3, + "hexcode": "1F400", + "label": "rat", + "order": 3534, + "tags": ["animal"], + "unicode": "🐀" + }, + { + "group": 3, + "hexcode": "1F439", + "label": "hamster", + "order": 3535, + "tags": ["animal", "face", "pet"], + "unicode": "🐹" + }, + { + "group": 3, + "hexcode": "1F430", + "label": "rabbit face", + "order": 3536, + "tags": ["animal", "bunny", "face", "pet", "rabbit"], + "unicode": "🐰" + }, + { + "group": 3, + "hexcode": "1F407", + "label": "rabbit", + "order": 3537, + "tags": ["animal", "bunny", "pet"], + "unicode": "🐇" + }, + { + "group": 3, + "hexcode": "1F43F", + "label": "chipmunk", + "order": 3539, + "tags": ["animal", "squirrel"], + "unicode": "🐿️" + }, + { + "group": 3, + "hexcode": "1F9AB", + "label": "beaver", + "order": 3540, + "tags": ["animal", "dam", "teeth"], + "unicode": "🦫" + }, + { + "group": 3, + "hexcode": "1F994", + "label": "hedgehog", + "order": 3541, + "tags": ["animal", "spiny"], + "unicode": "🦔" + }, + { + "group": 3, + "hexcode": "1F987", + "label": "bat", + "order": 3542, + "tags": ["animal", "vampire"], + "unicode": "🦇" + }, + { + "group": 3, + "hexcode": "1F43B", + "label": "bear", + "order": 3543, + "tags": ["animal", "face", "grizzly", "growl", "honey"], + "unicode": "🐻" + }, + { + "group": 3, + "hexcode": "1F43B-200D-2744-FE0F", + "label": "polar bear", + "order": 3544, + "tags": ["animal", "arctic", "bear", "polar", "white"], + "unicode": "🐻‍❄️" + }, + { + "group": 3, + "hexcode": "1F428", + "label": "koala", + "order": 3546, + "tags": [ + "animal", + "australia", + "bear", + "down", + "face", + "marsupial", + "under" + ], + "unicode": "🐨" + }, + { + "group": 3, + "hexcode": "1F43C", + "label": "panda", + "order": 3547, + "tags": ["animal", "bamboo", "face"], + "unicode": "🐼" + }, + { + "group": 3, + "hexcode": "1F9A5", + "label": "sloth", + "order": 3548, + "tags": ["lazy", "slow"], + "unicode": "🦥" + }, + { + "group": 3, + "hexcode": "1F9A6", + "label": "otter", + "order": 3549, + "tags": ["animal", "fishing", "playful"], + "unicode": "🦦" + }, + { + "group": 3, + "hexcode": "1F9A8", + "label": "skunk", + "order": 3550, + "tags": ["animal", "stink"], + "unicode": "🦨" + }, + { + "group": 3, + "hexcode": "1F998", + "label": "kangaroo", + "order": 3551, + "tags": ["animal", "joey", "jump", "marsupial"], + "unicode": "🦘" + }, + { + "group": 3, + "hexcode": "1F9A1", + "label": "badger", + "order": 3552, + "tags": ["animal", "honey", "pester"], + "unicode": "🦡" + }, + { + "group": 3, + "hexcode": "1F43E", + "label": "paw prints", + "order": 3553, + "tags": ["feet", "paw", "paws", "print", "prints"], + "unicode": "🐾" + }, + { + "group": 3, + "hexcode": "1F983", + "label": "turkey", + "order": 3554, + "tags": ["bird", "gobble", "thanksgiving"], + "unicode": "🦃" + }, + { + "group": 3, + "hexcode": "1F414", + "label": "chicken", + "order": 3555, + "tags": ["animal", "bird", "ornithology"], + "unicode": "🐔" + }, + { + "group": 3, + "hexcode": "1F413", + "label": "rooster", + "order": 3556, + "tags": ["animal", "bird", "ornithology"], + "unicode": "🐓" + }, + { + "group": 3, + "hexcode": "1F423", + "label": "hatching chick", + "order": 3557, + "tags": ["animal", "baby", "bird", "chick", "egg", "hatching"], + "unicode": "🐣" + }, + { + "group": 3, + "hexcode": "1F424", + "label": "baby chick", + "order": 3558, + "tags": ["animal", "baby", "bird", "chick", "ornithology"], + "unicode": "🐤" + }, + { + "group": 3, + "hexcode": "1F425", + "label": "front-facing baby chick", + "order": 3559, + "tags": [ + "animal", + "baby", + "bird", + "chick", + "front-facing", + "newborn", + "ornithology" + ], + "unicode": "🐥" + }, + { + "group": 3, + "hexcode": "1F426", + "label": "bird", + "order": 3560, + "tags": ["animal", "ornithology"], + "unicode": "🐦️" + }, + { + "group": 3, + "hexcode": "1F427", + "label": "penguin", + "order": 3561, + "tags": ["animal", "antarctica", "bird", "ornithology"], + "unicode": "🐧" + }, + { + "group": 3, + "hexcode": "1F54A", + "label": "dove", + "order": 3563, + "tags": ["bird", "fly", "ornithology", "peace"], + "unicode": "🕊️" + }, + { + "group": 3, + "hexcode": "1F985", + "label": "eagle", + "order": 3564, + "tags": ["animal", "bird", "ornithology"], + "unicode": "🦅" + }, + { + "group": 3, + "hexcode": "1F986", + "label": "duck", + "order": 3565, + "tags": ["animal", "bird", "ornithology"], + "unicode": "🦆" + }, + { + "group": 3, + "hexcode": "1F9A2", + "label": "swan", + "order": 3566, + "tags": ["animal", "bird", "cygnet", "duckling", "ornithology", "ugly"], + "unicode": "🦢" + }, + { + "group": 3, + "hexcode": "1F989", + "label": "owl", + "order": 3567, + "tags": ["animal", "bird", "ornithology", "wise"], + "unicode": "🦉" + }, + { + "group": 3, + "hexcode": "1F9A4", + "label": "dodo", + "order": 3568, + "tags": ["animal", "bird", "extinction", "large", "ornithology"], + "unicode": "🦤" + }, + { + "group": 3, + "hexcode": "1FAB6", + "label": "feather", + "order": 3569, + "tags": ["bird", "flight", "light", "plumage"], + "unicode": "🪶" + }, + { + "group": 3, + "hexcode": "1F9A9", + "label": "flamingo", + "order": 3570, + "tags": ["animal", "bird", "flamboyant", "ornithology", "tropical"], + "unicode": "🦩" + }, + { + "group": 3, + "hexcode": "1F99A", + "label": "peacock", + "order": 3571, + "tags": [ + "animal", + "bird", + "colorful", + "ornithology", + "ostentatious", + "peahen", + "pretty", + "proud" + ], + "unicode": "🦚" + }, + { + "group": 3, + "hexcode": "1F99C", + "label": "parrot", + "order": 3572, + "tags": ["animal", "bird", "ornithology", "pirate", "talk"], + "unicode": "🦜" + }, + { + "group": 3, + "hexcode": "1FABD", + "label": "wing", + "order": 3573, + "tags": [ + "angelic", + "ascend", + "aviation", + "bird", + "fly", + "flying", + "heavenly", + "mythology", + "soar" + ], + "unicode": "🪽" + }, + { + "group": 3, + "hexcode": "1F426-200D-2B1B", + "label": "black bird", + "order": 3574, + "tags": [ + "animal", + "beak", + "bird", + "black", + "caw", + "corvid", + "crow", + "ornithology", + "raven", + "rook" + ], + "unicode": "🐦‍⬛" + }, + { + "group": 3, + "hexcode": "1FABF", + "label": "goose", + "order": 3575, + "tags": [ + "animal", + "bird", + "duck", + "flock", + "fowl", + "gaggle", + "gander", + "geese", + "honk", + "ornithology", + "silly" + ], + "unicode": "🪿" + }, + { + "group": 3, + "hexcode": "1F426-200D-1F525", + "label": "phoenix", + "order": 3576, + "tags": [ + "ascend", + "ascension", + "emerge", + "fantasy", + "firebird", + "glory", + "immortal", + "rebirth", + "reincarnation", + "reinvent", + "renewal", + "revival", + "revive", + "rise", + "transform" + ], + "unicode": "🐦‍🔥" + }, + { + "group": 3, + "hexcode": "1F438", + "label": "frog", + "order": 3577, + "tags": ["animal", "face"], + "unicode": "🐸" + }, + { + "group": 3, + "hexcode": "1F40A", + "label": "crocodile", + "order": 3578, + "tags": ["animal", "zoo"], + "unicode": "🐊" + }, + { + "group": 3, + "hexcode": "1F422", + "label": "turtle", + "order": 3579, + "tags": ["animal", "terrapin", "tortoise"], + "unicode": "🐢" + }, + { + "group": 3, + "hexcode": "1F98E", + "label": "lizard", + "order": 3580, + "tags": ["animal", "reptile"], + "unicode": "🦎" + }, + { + "group": 3, + "hexcode": "1F40D", + "label": "snake", + "order": 3581, + "tags": ["animal", "bearer", "ophiuchus", "serpent", "zodiac"], + "unicode": "🐍" + }, + { + "group": 3, + "hexcode": "1F432", + "label": "dragon face", + "order": 3582, + "tags": ["animal", "dragon", "face", "fairy", "fairytale", "tale"], + "unicode": "🐲" + }, + { + "group": 3, + "hexcode": "1F409", + "label": "dragon", + "order": 3583, + "tags": ["animal", "fairy", "fairytale", "knights", "tale"], + "unicode": "🐉" + }, + { + "group": 3, + "hexcode": "1F995", + "label": "sauropod", + "order": 3584, + "tags": ["brachiosaurus", "brontosaurus", "dinosaur", "diplodocus"], + "unicode": "🦕" + }, + { + "group": 3, + "hexcode": "1F996", + "label": "T-Rex", + "order": 3585, + "tags": ["dinosaur", "rex", "t", "t-rex", "tyrannosaurus"], + "unicode": "🦖" + }, + { + "group": 3, + "hexcode": "1F433", + "label": "spouting whale", + "order": 3586, + "tags": ["animal", "beach", "face", "ocean", "spouting", "whale"], + "unicode": "🐳" + }, + { + "group": 3, + "hexcode": "1F40B", + "label": "whale", + "order": 3587, + "tags": ["animal", "beach", "ocean"], + "unicode": "🐋" + }, + { + "group": 3, + "hexcode": "1F42C", + "label": "dolphin", + "order": 3588, + "tags": ["animal", "beach", "flipper", "ocean"], + "unicode": "🐬" + }, + { + "group": 3, + "hexcode": "1F9AD", + "label": "seal", + "order": 3589, + "tags": ["animal", "lion", "ocean", "sea"], + "unicode": "🦭" + }, + { + "group": 3, + "hexcode": "1F41F", + "label": "fish", + "order": 3590, + "tags": ["animal", "dinner", "fishes", "fishing", "pisces", "zodiac"], + "unicode": "🐟️" + }, + { + "group": 3, + "hexcode": "1F420", + "label": "tropical fish", + "order": 3591, + "tags": ["animal", "fish", "fishes", "tropical"], + "unicode": "🐠" + }, + { + "group": 3, + "hexcode": "1F421", + "label": "blowfish", + "order": 3592, + "tags": ["animal", "fish"], + "unicode": "🐡" + }, + { + "group": 3, + "hexcode": "1F988", + "label": "shark", + "order": 3593, + "tags": ["animal", "fish"], + "unicode": "🦈" + }, + { + "group": 3, + "hexcode": "1F419", + "label": "octopus", + "order": 3594, + "tags": ["animal", "creature", "ocean"], + "unicode": "🐙" + }, + { + "group": 3, + "hexcode": "1F41A", + "label": "spiral shell", + "order": 3595, + "tags": ["animal", "beach", "conch", "sea", "shell", "spiral"], + "unicode": "🐚" + }, + { + "group": 3, + "hexcode": "1FAB8", + "label": "coral", + "order": 3596, + "tags": ["change", "climate", "ocean", "reef", "sea"], + "unicode": "🪸" + }, + { + "group": 3, + "hexcode": "1FABC", + "label": "jellyfish", + "order": 3597, + "tags": [ + "animal", + "aquarium", + "burn", + "invertebrate", + "jelly", + "life", + "marine", + "ocean", + "ouch", + "plankton", + "sea", + "sting", + "stinger", + "tentacles" + ], + "unicode": "🪼" + }, + { + "group": 3, + "hexcode": "1F980", + "label": "crab", + "order": 3598, + "tags": ["cancer", "zodiac"], + "unicode": "🦀" + }, + { + "group": 3, + "hexcode": "1F99E", + "label": "lobster", + "order": 3599, + "tags": ["animal", "bisque", "claws", "seafood"], + "unicode": "🦞" + }, + { + "group": 3, + "hexcode": "1F990", + "label": "shrimp", + "order": 3600, + "tags": ["food", "shellfish", "small"], + "unicode": "🦐" + }, + { + "group": 3, + "hexcode": "1F991", + "label": "squid", + "order": 3601, + "tags": ["animal", "food", "mollusk"], + "unicode": "🦑" + }, + { + "group": 3, + "hexcode": "1F9AA", + "label": "oyster", + "order": 3602, + "tags": ["diving", "pearl"], + "unicode": "🦪" + }, + { + "group": 3, + "hexcode": "1F40C", + "label": "snail", + "order": 3603, + "tags": ["animal", "escargot", "garden", "nature", "slug"], + "unicode": "🐌" + }, + { + "group": 3, + "hexcode": "1F98B", + "label": "butterfly", + "order": 3604, + "tags": ["insect", "pretty"], + "unicode": "🦋" + }, + { + "group": 3, + "hexcode": "1F41B", + "label": "bug", + "order": 3605, + "tags": ["animal", "garden", "insect"], + "unicode": "🐛" + }, + { + "group": 3, + "hexcode": "1F41C", + "label": "ant", + "order": 3606, + "tags": ["animal", "garden", "insect"], + "unicode": "🐜" + }, + { + "group": 3, + "hexcode": "1F41D", + "label": "honeybee", + "order": 3607, + "tags": [ + "animal", + "bee", + "bumblebee", + "honey", + "insect", + "nature", + "spring" + ], + "unicode": "🐝" + }, + { + "group": 3, + "hexcode": "1FAB2", + "label": "beetle", + "order": 3608, + "tags": ["animal", "bug", "insect"], + "unicode": "🪲" + }, + { + "group": 3, + "hexcode": "1F41E", + "label": "lady beetle", + "order": 3609, + "tags": [ + "animal", + "beetle", + "garden", + "insect", + "lady", + "ladybird", + "ladybug", + "nature" + ], + "unicode": "🐞" + }, + { + "group": 3, + "hexcode": "1F997", + "label": "cricket", + "order": 3610, + "tags": ["animal", "bug", "grasshopper", "insect", "orthoptera"], + "unicode": "🦗" + }, + { + "group": 3, + "hexcode": "1FAB3", + "label": "cockroach", + "order": 3611, + "tags": ["animal", "insect", "pest", "roach"], + "unicode": "🪳" + }, + { + "group": 3, + "hexcode": "1F577", + "label": "spider", + "order": 3613, + "tags": ["animal", "insect"], + "unicode": "🕷️" + }, + { + "group": 3, + "hexcode": "1F578", + "label": "spider web", + "order": 3615, + "tags": ["spider", "web"], + "unicode": "🕸️" + }, + { + "group": 3, + "hexcode": "1F982", + "label": "scorpion", + "order": 3616, + "tags": ["scorpio", "scorpius", "zodiac"], + "unicode": "🦂" + }, + { + "group": 3, + "hexcode": "1F99F", + "label": "mosquito", + "order": 3617, + "tags": [ + "bite", + "disease", + "fever", + "insect", + "malaria", + "pest", + "virus" + ], + "unicode": "🦟" + }, + { + "group": 3, + "hexcode": "1FAB0", + "label": "fly", + "order": 3618, + "tags": ["animal", "disease", "insect", "maggot", "pest", "rotting"], + "unicode": "🪰" + }, + { + "group": 3, + "hexcode": "1FAB1", + "label": "worm", + "order": 3619, + "tags": ["animal", "annelid", "earthworm", "parasite"], + "unicode": "🪱" + }, + { + "group": 3, + "hexcode": "1F9A0", + "label": "microbe", + "order": 3620, + "tags": ["amoeba", "bacteria", "science", "virus"], + "unicode": "🦠" + }, + { + "group": 3, + "hexcode": "1F490", + "label": "bouquet", + "order": 3621, + "tags": [ + "anniversary", + "birthday", + "date", + "flower", + "love", + "plant", + "romance" + ], + "unicode": "💐" + }, + { + "group": 3, + "hexcode": "1F338", + "label": "cherry blossom", + "order": 3622, + "tags": [ + "blossom", + "cherry", + "flower", + "plant", + "spring", + "springtime" + ], + "unicode": "🌸" + }, + { + "group": 3, + "hexcode": "1F4AE", + "label": "white flower", + "order": 3623, + "tags": ["flower", "white"], + "unicode": "💮" + }, + { + "group": 3, + "hexcode": "1FAB7", + "label": "lotus", + "order": 3624, + "tags": [ + "beauty", + "buddhism", + "calm", + "flower", + "hinduism", + "peace", + "purity", + "serenity" + ], + "unicode": "🪷" + }, + { + "group": 3, + "hexcode": "1F3F5", + "label": "rosette", + "order": 3626, + "tags": ["plant"], + "unicode": "🏵️" + }, + { + "group": 3, + "hexcode": "1F339", + "label": "rose", + "order": 3627, + "tags": [ + "beauty", + "elegant", + "flower", + "love", + "plant", + "red", + "valentine" + ], + "unicode": "🌹" + }, + { + "group": 3, + "hexcode": "1F940", + "label": "wilted flower", + "order": 3628, + "tags": ["dying", "flower", "wilted"], + "unicode": "🥀" + }, + { + "group": 3, + "hexcode": "1F33A", + "label": "hibiscus", + "order": 3629, + "tags": ["flower", "plant"], + "unicode": "🌺" + }, + { + "group": 3, + "hexcode": "1F33B", + "label": "sunflower", + "order": 3630, + "tags": ["flower", "outdoors", "plant", "sun"], + "unicode": "🌻" + }, + { + "group": 3, + "hexcode": "1F33C", + "label": "blossom", + "order": 3631, + "tags": ["buttercup", "dandelion", "flower", "plant"], + "unicode": "🌼" + }, + { + "group": 3, + "hexcode": "1F337", + "label": "tulip", + "order": 3632, + "tags": ["blossom", "flower", "growth", "plant"], + "unicode": "🌷" + }, + { + "group": 3, + "hexcode": "1FABB", + "label": "hyacinth", + "order": 3633, + "tags": [ + "bloom", + "bluebonnet", + "flower", + "indigo", + "lavender", + "lilac", + "lupine", + "plant", + "purple", + "shrub", + "snapdragon", + "spring", + "violet" + ], + "unicode": "🪻" + }, + { + "group": 3, + "hexcode": "1F331", + "label": "seedling", + "order": 3634, + "tags": ["plant", "sapling", "sprout", "young"], + "unicode": "🌱" + }, + { + "group": 3, + "hexcode": "1FAB4", + "label": "potted plant", + "order": 3635, + "tags": [ + "decor", + "grow", + "house", + "nurturing", + "plant", + "pot", + "potted" + ], + "unicode": "🪴" + }, + { + "group": 3, + "hexcode": "1F332", + "label": "evergreen tree", + "order": 3636, + "tags": ["christmas", "evergreen", "forest", "pine", "tree"], + "unicode": "🌲" + }, + { + "group": 3, + "hexcode": "1F333", + "label": "deciduous tree", + "order": 3637, + "tags": ["deciduous", "forest", "green", "habitat", "shedding", "tree"], + "unicode": "🌳" + }, + { + "group": 3, + "hexcode": "1F334", + "label": "palm tree", + "order": 3638, + "tags": ["beach", "palm", "plant", "tree", "tropical"], + "unicode": "🌴" + }, + { + "group": 3, + "hexcode": "1F335", + "label": "cactus", + "order": 3639, + "tags": ["desert", "drought", "nature", "plant"], + "unicode": "🌵" + }, + { + "group": 3, + "hexcode": "1F33E", + "label": "sheaf of rice", + "order": 3640, + "tags": ["ear", "grain", "grains", "plant", "rice", "sheaf"], + "unicode": "🌾" + }, + { + "group": 3, + "hexcode": "1F33F", + "label": "herb", + "order": 3641, + "tags": ["leaf", "plant"], + "unicode": "🌿" + }, + { + "group": 3, + "hexcode": "2618", + "label": "shamrock", + "order": 3643, + "tags": ["irish", "plant"], + "unicode": "☘️" + }, + { + "group": 3, + "hexcode": "1F340", + "label": "four leaf clover", + "order": 3644, + "tags": [ + "4", + "clover", + "four", + "four-leaf", + "irish", + "leaf", + "lucky", + "plant" + ], + "unicode": "🍀" + }, + { + "group": 3, + "hexcode": "1F341", + "label": "maple leaf", + "order": 3645, + "tags": ["falling", "leaf", "maple"], + "unicode": "🍁" + }, + { + "group": 3, + "hexcode": "1F342", + "label": "fallen leaf", + "order": 3646, + "tags": ["autumn", "fall", "fallen", "falling", "leaf"], + "unicode": "🍂" + }, + { + "group": 3, + "hexcode": "1F343", + "label": "leaf fluttering in wind", + "order": 3647, + "tags": ["blow", "flutter", "fluttering", "leaf", "wind"], + "unicode": "🍃" + }, + { + "group": 3, + "hexcode": "1FAB9", + "label": "empty nest", + "order": 3648, + "tags": ["branch", "empty", "home", "nest", "nesting"], + "unicode": "🪹" + }, + { + "group": 3, + "hexcode": "1FABA", + "label": "nest with eggs", + "order": 3649, + "tags": ["bird", "branch", "egg", "eggs", "nest", "nesting"], + "unicode": "🪺" + }, + { + "group": 3, + "hexcode": "1F344", + "label": "mushroom", + "order": 3650, + "tags": ["fungus", "toadstool"], + "unicode": "🍄" + }, + { + "group": 3, + "hexcode": "1FABE", + "label": "leafless tree", + "order": 3651, + "tags": [ + "bare", + "barren", + "branches", + "dead", + "drought", + "leafless", + "tree", + "trunk", + "winter", + "wood" + ], + "unicode": "🪾" + } + ] + }, + { + "name": "Food & Drink", + "emojis": [ + { + "group": 4, + "hexcode": "1F347", + "label": "grapes", + "order": 3652, + "tags": ["dionysus", "fruit", "grape"], + "unicode": "🍇" + }, + { + "group": 4, + "hexcode": "1F348", + "label": "melon", + "order": 3653, + "tags": ["cantaloupe", "fruit"], + "unicode": "🍈" + }, + { + "group": 4, + "hexcode": "1F349", + "label": "watermelon", + "order": 3654, + "tags": ["fruit"], + "unicode": "🍉" + }, + { + "group": 4, + "hexcode": "1F34A", + "label": "tangerine", + "order": 3655, + "tags": ["c", "citrus", "fruit", "nectarine", "orange", "vitamin"], + "unicode": "🍊" + }, + { + "group": 4, + "hexcode": "1F34B", + "label": "lemon", + "order": 3656, + "tags": ["citrus", "fruit", "sour"], + "unicode": "🍋" + }, + { + "group": 4, + "hexcode": "1F34B-200D-1F7E9", + "label": "lime", + "order": 3657, + "tags": [ + "acidity", + "citrus", + "cocktail", + "fruit", + "garnish", + "key", + "margarita", + "mojito", + "refreshing", + "salsa", + "sour", + "tangy", + "tequila", + "tropical", + "zest" + ], + "unicode": "🍋‍🟩" + }, + { + "group": 4, + "hexcode": "1F34C", + "label": "banana", + "order": 3658, + "tags": ["fruit", "potassium"], + "unicode": "🍌" + }, + { + "group": 4, + "hexcode": "1F34D", + "label": "pineapple", + "order": 3659, + "tags": ["colada", "fruit", "pina", "tropical"], + "unicode": "🍍" + }, + { + "group": 4, + "hexcode": "1F96D", + "label": "mango", + "order": 3660, + "tags": ["food", "fruit", "tropical"], + "unicode": "🥭" + }, + { + "group": 4, + "hexcode": "1F34E", + "label": "red apple", + "order": 3661, + "tags": ["apple", "diet", "food", "fruit", "health", "red", "ripe"], + "unicode": "🍎" + }, + { + "group": 4, + "hexcode": "1F34F", + "label": "green apple", + "order": 3662, + "tags": ["apple", "fruit", "green"], + "unicode": "🍏" + }, + { + "group": 4, + "hexcode": "1F350", + "label": "pear", + "order": 3663, + "tags": ["fruit"], + "unicode": "🍐" + }, + { + "group": 4, + "hexcode": "1F351", + "label": "peach", + "order": 3664, + "tags": ["fruit"], + "unicode": "🍑" + }, + { + "group": 4, + "hexcode": "1F352", + "label": "cherries", + "order": 3665, + "tags": ["berries", "cherry", "fruit", "red"], + "unicode": "🍒" + }, + { + "group": 4, + "hexcode": "1F353", + "label": "strawberry", + "order": 3666, + "tags": ["berry", "fruit"], + "unicode": "🍓" + }, + { + "group": 4, + "hexcode": "1FAD0", + "label": "blueberries", + "order": 3667, + "tags": [ + "berries", + "berry", + "bilberry", + "blue", + "blueberry", + "food", + "fruit" + ], + "unicode": "🫐" + }, + { + "group": 4, + "hexcode": "1F95D", + "label": "kiwi fruit", + "order": 3668, + "tags": ["food", "fruit", "kiwi"], + "unicode": "🥝" + }, + { + "group": 4, + "hexcode": "1F345", + "label": "tomato", + "order": 3669, + "tags": ["food", "fruit", "vegetable"], + "unicode": "🍅" + }, + { + "group": 4, + "hexcode": "1FAD2", + "label": "olive", + "order": 3670, + "tags": ["food"], + "unicode": "🫒" + }, + { + "group": 4, + "hexcode": "1F965", + "label": "coconut", + "order": 3671, + "tags": ["colada", "palm", "piña"], + "unicode": "🥥" + }, + { + "group": 4, + "hexcode": "1F951", + "label": "avocado", + "order": 3672, + "tags": ["food", "fruit"], + "unicode": "🥑" + }, + { + "group": 4, + "hexcode": "1F346", + "label": "eggplant", + "order": 3673, + "tags": ["aubergine", "vegetable"], + "unicode": "🍆" + }, + { + "group": 4, + "hexcode": "1F954", + "label": "potato", + "order": 3674, + "tags": ["food", "vegetable"], + "unicode": "🥔" + }, + { + "group": 4, + "hexcode": "1F955", + "label": "carrot", + "order": 3675, + "tags": ["food", "vegetable"], + "unicode": "🥕" + }, + { + "group": 4, + "hexcode": "1F33D", + "label": "ear of corn", + "order": 3676, + "tags": ["corn", "crops", "ear", "farm", "maize", "maze"], + "unicode": "🌽" + }, + { + "group": 4, + "hexcode": "1F336", + "label": "hot pepper", + "order": 3678, + "tags": ["hot", "pepper"], + "unicode": "🌶️" + }, + { + "group": 4, + "hexcode": "1FAD1", + "label": "bell pepper", + "order": 3679, + "tags": ["bell", "capsicum", "food", "pepper", "vegetable"], + "unicode": "🫑" + }, + { + "group": 4, + "hexcode": "1F952", + "label": "cucumber", + "order": 3680, + "tags": ["food", "pickle", "vegetable"], + "unicode": "🥒" + }, + { + "group": 4, + "hexcode": "1F96C", + "label": "leafy green", + "order": 3681, + "tags": [ + "bok", + "burgers", + "cabbage", + "choy", + "green", + "kale", + "leafy", + "lettuce", + "salad" + ], + "unicode": "🥬" + }, + { + "group": 4, + "hexcode": "1F966", + "label": "broccoli", + "order": 3682, + "tags": ["cabbage", "wild"], + "unicode": "🥦" + }, + { + "group": 4, + "hexcode": "1F9C4", + "label": "garlic", + "order": 3683, + "tags": ["flavoring"], + "unicode": "🧄" + }, + { + "group": 4, + "hexcode": "1F9C5", + "label": "onion", + "order": 3684, + "tags": ["flavoring"], + "unicode": "🧅" + }, + { + "group": 4, + "hexcode": "1F95C", + "label": "peanuts", + "order": 3685, + "tags": ["food", "nut", "peanut", "vegetable"], + "unicode": "🥜" + }, + { + "group": 4, + "hexcode": "1FAD8", + "label": "beans", + "order": 3686, + "tags": ["food", "kidney", "legume", "small"], + "unicode": "🫘" + }, + { + "group": 4, + "hexcode": "1F330", + "label": "chestnut", + "order": 3687, + "tags": ["almond", "plant"], + "unicode": "🌰" + }, + { + "group": 4, + "hexcode": "1FADA", + "label": "ginger root", + "order": 3688, + "tags": [ + "beer", + "ginger", + "health", + "herb", + "natural", + "root", + "spice" + ], + "unicode": "🫚" + }, + { + "group": 4, + "hexcode": "1FADB", + "label": "pea pod", + "order": 3689, + "tags": [ + "beans", + "beanstalk", + "edamame", + "legume", + "pea", + "pod", + "soybean", + "vegetable", + "veggie" + ], + "unicode": "🫛" + }, + { + "group": 4, + "hexcode": "1F344-200D-1F7EB", + "label": "brown mushroom", + "order": 3690, + "tags": [ + "food", + "fungi", + "fungus", + "mushroom", + "nature", + "pizza", + "portobello", + "shiitake", + "shroom", + "spore", + "sprout", + "toppings", + "truffle", + "vegetable", + "vegetarian", + "veggie" + ], + "unicode": "🍄‍🟫" + }, + { + "group": 4, + "hexcode": "1FADC", + "label": "root vegetable", + "order": 3691, + "tags": [ + "beet", + "food", + "garden", + "radish", + "root", + "salad", + "turnip", + "vegetable", + "vegetarian" + ], + "unicode": "🫜" + }, + { + "group": 4, + "hexcode": "1F35E", + "label": "bread", + "order": 3692, + "tags": [ + "carbs", + "food", + "grain", + "loaf", + "restaurant", + "toast", + "wheat" + ], + "unicode": "🍞" + }, + { + "group": 4, + "hexcode": "1F950", + "label": "croissant", + "order": 3693, + "tags": ["bread", "breakfast", "crescent", "food", "french", "roll"], + "unicode": "🥐" + }, + { + "group": 4, + "hexcode": "1F956", + "label": "baguette bread", + "order": 3694, + "tags": ["baguette", "bread", "food", "french"], + "unicode": "🥖" + }, + { + "group": 4, + "hexcode": "1FAD3", + "label": "flatbread", + "order": 3695, + "tags": ["arepa", "bread", "food", "gordita", "lavash", "naan", "pita"], + "unicode": "🫓" + }, + { + "group": 4, + "hexcode": "1F968", + "label": "pretzel", + "order": 3696, + "tags": ["convoluted", "twisted"], + "unicode": "🥨" + }, + { + "group": 4, + "hexcode": "1F96F", + "label": "bagel", + "order": 3697, + "tags": ["bakery", "bread", "breakfast", "schmear"], + "unicode": "🥯" + }, + { + "group": 4, + "hexcode": "1F95E", + "label": "pancakes", + "order": 3698, + "tags": ["breakfast", "crêpe", "food", "hotcake", "pancake"], + "unicode": "🥞" + }, + { + "group": 4, + "hexcode": "1F9C7", + "label": "waffle", + "order": 3699, + "tags": ["breakfast", "indecisive", "iron"], + "unicode": "🧇" + }, + { + "group": 4, + "hexcode": "1F9C0", + "label": "cheese wedge", + "order": 3700, + "tags": ["cheese", "wedge"], + "unicode": "🧀" + }, + { + "group": 4, + "hexcode": "1F356", + "label": "meat on bone", + "order": 3701, + "tags": ["bone", "meat"], + "unicode": "🍖" + }, + { + "group": 4, + "hexcode": "1F357", + "label": "poultry leg", + "order": 3702, + "tags": [ + "bone", + "chicken", + "drumstick", + "hungry", + "leg", + "poultry", + "turkey" + ], + "unicode": "🍗" + }, + { + "group": 4, + "hexcode": "1F969", + "label": "cut of meat", + "order": 3703, + "tags": ["chop", "cut", "lambchop", "meat", "porkchop", "red", "steak"], + "unicode": "🥩" + }, + { + "group": 4, + "hexcode": "1F953", + "label": "bacon", + "order": 3704, + "tags": ["breakfast", "food", "meat"], + "unicode": "🥓" + }, + { + "group": 4, + "hexcode": "1F354", + "label": "hamburger", + "order": 3705, + "tags": ["burger", "eat", "fast", "food", "hungry"], + "unicode": "🍔" + }, + { + "group": 4, + "hexcode": "1F35F", + "label": "french fries", + "order": 3706, + "tags": ["fast", "food", "french", "fries"], + "unicode": "🍟" + }, + { + "group": 4, + "hexcode": "1F355", + "label": "pizza", + "order": 3707, + "tags": ["cheese", "food", "hungry", "pepperoni", "slice"], + "unicode": "🍕" + }, + { + "group": 4, + "hexcode": "1F32D", + "label": "hot dog", + "order": 3708, + "tags": ["dog", "frankfurter", "hot", "hotdog", "sausage"], + "unicode": "🌭" + }, + { + "group": 4, + "hexcode": "1F96A", + "label": "sandwich", + "order": 3709, + "tags": ["bread"], + "unicode": "🥪" + }, + { + "group": 4, + "hexcode": "1F32E", + "label": "taco", + "order": 3710, + "tags": ["mexican"], + "unicode": "🌮" + }, + { + "group": 4, + "hexcode": "1F32F", + "label": "burrito", + "order": 3711, + "tags": ["mexican", "wrap"], + "unicode": "🌯" + }, + { + "group": 4, + "hexcode": "1FAD4", + "label": "tamale", + "order": 3712, + "tags": ["food", "mexican", "pamonha", "wrapped"], + "unicode": "🫔" + }, + { + "group": 4, + "hexcode": "1F959", + "label": "stuffed flatbread", + "order": 3713, + "tags": ["falafel", "flatbread", "food", "gyro", "kebab", "stuffed"], + "unicode": "🥙" + }, + { + "group": 4, + "hexcode": "1F9C6", + "label": "falafel", + "order": 3714, + "tags": ["chickpea", "meatball"], + "unicode": "🧆" + }, + { + "group": 4, + "hexcode": "1F95A", + "label": "egg", + "order": 3715, + "tags": ["breakfast", "food"], + "unicode": "🥚" + }, + { + "group": 4, + "hexcode": "1F373", + "label": "cooking", + "order": 3716, + "tags": [ + "breakfast", + "easy", + "egg", + "fry", + "frying", + "over", + "pan", + "restaurant", + "side", + "sunny", + "up" + ], + "unicode": "🍳" + }, + { + "group": 4, + "hexcode": "1F958", + "label": "shallow pan of food", + "order": 3717, + "tags": ["casserole", "food", "paella", "pan", "shallow"], + "unicode": "🥘" + }, + { + "group": 4, + "hexcode": "1F372", + "label": "pot of food", + "order": 3718, + "tags": ["food", "pot", "soup", "stew"], + "unicode": "🍲" + }, + { + "group": 4, + "hexcode": "1FAD5", + "label": "fondue", + "order": 3719, + "tags": ["cheese", "chocolate", "food", "melted", "pot", "ski"], + "unicode": "🫕" + }, + { + "group": 4, + "hexcode": "1F963", + "label": "bowl with spoon", + "order": 3720, + "tags": [ + "bowl", + "breakfast", + "cereal", + "congee", + "oatmeal", + "porridge", + "spoon" + ], + "unicode": "🥣" + }, + { + "group": 4, + "hexcode": "1F957", + "label": "green salad", + "order": 3721, + "tags": ["food", "green", "salad"], + "unicode": "🥗" + }, + { + "group": 4, + "hexcode": "1F37F", + "label": "popcorn", + "order": 3722, + "tags": ["corn", "movie", "pop"], + "unicode": "🍿" + }, + { + "group": 4, + "hexcode": "1F9C8", + "label": "butter", + "order": 3723, + "tags": ["dairy"], + "unicode": "🧈" + }, + { + "group": 4, + "hexcode": "1F9C2", + "label": "salt", + "order": 3724, + "tags": [ + "condiment", + "flavor", + "mad", + "salty", + "shaker", + "taste", + "upset" + ], + "unicode": "🧂" + }, + { + "group": 4, + "hexcode": "1F96B", + "label": "canned food", + "order": 3725, + "tags": ["can", "canned", "food"], + "unicode": "🥫" + }, + { + "group": 4, + "hexcode": "1F371", + "label": "bento box", + "order": 3726, + "tags": ["bento", "box", "food"], + "unicode": "🍱" + }, + { + "group": 4, + "hexcode": "1F358", + "label": "rice cracker", + "order": 3727, + "tags": ["cracker", "food", "rice"], + "unicode": "🍘" + }, + { + "group": 4, + "hexcode": "1F359", + "label": "rice ball", + "order": 3728, + "tags": ["ball", "food", "japanese", "rice"], + "unicode": "🍙" + }, + { + "group": 4, + "hexcode": "1F35A", + "label": "cooked rice", + "order": 3729, + "tags": ["cooked", "food", "rice"], + "unicode": "🍚" + }, + { + "group": 4, + "hexcode": "1F35B", + "label": "curry rice", + "order": 3730, + "tags": ["curry", "food", "rice"], + "unicode": "🍛" + }, + { + "group": 4, + "hexcode": "1F35C", + "label": "steaming bowl", + "order": 3731, + "tags": [ + "bowl", + "chopsticks", + "food", + "noodle", + "pho", + "ramen", + "soup", + "steaming" + ], + "unicode": "🍜" + }, + { + "group": 4, + "hexcode": "1F35D", + "label": "spaghetti", + "order": 3732, + "tags": ["food", "meatballs", "pasta", "restaurant"], + "unicode": "🍝" + }, + { + "group": 4, + "hexcode": "1F360", + "label": "roasted sweet potato", + "order": 3733, + "tags": ["food", "potato", "roasted", "sweet"], + "unicode": "🍠" + }, + { + "group": 4, + "hexcode": "1F362", + "label": "oden", + "order": 3734, + "tags": ["food", "kebab", "restaurant", "seafood", "skewer", "stick"], + "unicode": "🍢" + }, + { + "group": 4, + "hexcode": "1F363", + "label": "sushi", + "order": 3735, + "tags": ["food"], + "unicode": "🍣" + }, + { + "group": 4, + "hexcode": "1F364", + "label": "fried shrimp", + "order": 3736, + "tags": ["fried", "prawn", "shrimp", "tempura"], + "unicode": "🍤" + }, + { + "group": 4, + "hexcode": "1F365", + "label": "fish cake with swirl", + "order": 3737, + "tags": ["cake", "fish", "food", "pastry", "restaurant", "swirl"], + "unicode": "🍥" + }, + { + "group": 4, + "hexcode": "1F96E", + "label": "moon cake", + "order": 3738, + "tags": ["autumn", "cake", "festival", "moon", "yuèbǐng"], + "unicode": "🥮" + }, + { + "group": 4, + "hexcode": "1F361", + "label": "dango", + "order": 3739, + "tags": ["dessert", "japanese", "skewer", "stick", "sweet"], + "unicode": "🍡" + }, + { + "group": 4, + "hexcode": "1F95F", + "label": "dumpling", + "order": 3740, + "tags": ["empanada", "gyōza", "jiaozi", "pierogi", "potsticker"], + "unicode": "🥟" + }, + { + "group": 4, + "hexcode": "1F960", + "label": "fortune cookie", + "order": 3741, + "tags": ["cookie", "fortune", "prophecy"], + "unicode": "🥠" + }, + { + "group": 4, + "hexcode": "1F961", + "label": "takeout box", + "order": 3742, + "tags": [ + "box", + "chopsticks", + "delivery", + "food", + "oyster", + "pail", + "takeout" + ], + "unicode": "🥡" + }, + { + "group": 4, + "hexcode": "1F366", + "label": "soft ice cream", + "order": 3743, + "tags": [ + "cream", + "dessert", + "food", + "ice", + "icecream", + "restaurant", + "serve", + "soft", + "sweet" + ], + "unicode": "🍦" + }, + { + "group": 4, + "hexcode": "1F367", + "label": "shaved ice", + "order": 3744, + "tags": ["dessert", "ice", "restaurant", "shaved", "sweet"], + "unicode": "🍧" + }, + { + "group": 4, + "hexcode": "1F368", + "label": "ice cream", + "order": 3745, + "tags": ["cream", "dessert", "food", "ice", "restaurant", "sweet"], + "unicode": "🍨" + }, + { + "group": 4, + "hexcode": "1F369", + "label": "doughnut", + "order": 3746, + "tags": ["breakfast", "dessert", "donut", "food", "sweet"], + "unicode": "🍩" + }, + { + "group": 4, + "hexcode": "1F36A", + "label": "cookie", + "order": 3747, + "tags": ["chip", "chocolate", "dessert", "sweet"], + "unicode": "🍪" + }, + { + "group": 4, + "hexcode": "1F382", + "label": "birthday cake", + "order": 3748, + "tags": [ + "bday", + "birthday", + "cake", + "celebration", + "dessert", + "happy", + "pastry", + "sweet" + ], + "unicode": "🎂" + }, + { + "group": 4, + "hexcode": "1F370", + "label": "shortcake", + "order": 3749, + "tags": ["cake", "dessert", "pastry", "slice", "sweet"], + "unicode": "🍰" + }, + { + "group": 4, + "hexcode": "1F9C1", + "label": "cupcake", + "order": 3750, + "tags": ["bakery", "dessert", "sprinkles", "sugar", "sweet", "treat"], + "unicode": "🧁" + }, + { + "group": 4, + "hexcode": "1F967", + "label": "pie", + "order": 3751, + "tags": [ + "apple", + "filling", + "fruit", + "meat", + "pastry", + "pumpkin", + "slice" + ], + "unicode": "🥧" + }, + { + "group": 4, + "hexcode": "1F36B", + "label": "chocolate bar", + "order": 3752, + "tags": [ + "bar", + "candy", + "chocolate", + "dessert", + "halloween", + "sweet", + "tooth" + ], + "unicode": "🍫" + }, + { + "group": 4, + "hexcode": "1F36C", + "label": "candy", + "order": 3753, + "tags": [ + "cavities", + "dessert", + "halloween", + "restaurant", + "sweet", + "tooth", + "wrapper" + ], + "unicode": "🍬" + }, + { + "group": 4, + "hexcode": "1F36D", + "label": "lollipop", + "order": 3754, + "tags": ["candy", "dessert", "food", "restaurant", "sweet"], + "unicode": "🍭" + }, + { + "group": 4, + "hexcode": "1F36E", + "label": "custard", + "order": 3755, + "tags": ["dessert", "pudding", "sweet"], + "unicode": "🍮" + }, + { + "group": 4, + "hexcode": "1F36F", + "label": "honey pot", + "order": 3756, + "tags": [ + "barrel", + "bear", + "food", + "honey", + "honeypot", + "jar", + "pot", + "sweet" + ], + "unicode": "🍯" + }, + { + "group": 4, + "hexcode": "1F37C", + "label": "baby bottle", + "order": 3757, + "tags": [ + "babies", + "baby", + "birth", + "born", + "bottle", + "drink", + "infant", + "milk", + "newborn" + ], + "unicode": "🍼" + }, + { + "group": 4, + "hexcode": "1F95B", + "label": "glass of milk", + "order": 3758, + "tags": ["drink", "glass", "milk"], + "unicode": "🥛" + }, + { + "group": 4, + "hexcode": "2615", + "label": "hot beverage", + "order": 3759, + "tags": [ + "beverage", + "cafe", + "caffeine", + "chai", + "coffee", + "drink", + "hot", + "morning", + "steaming", + "tea" + ], + "unicode": "☕️" + }, + { + "group": 4, + "hexcode": "1FAD6", + "label": "teapot", + "order": 3760, + "tags": ["brew", "drink", "food", "pot", "tea"], + "unicode": "🫖" + }, + { + "group": 4, + "hexcode": "1F375", + "label": "teacup without handle", + "order": 3761, + "tags": [ + "beverage", + "cup", + "drink", + "handle", + "oolong", + "tea", + "teacup" + ], + "unicode": "🍵" + }, + { + "group": 4, + "hexcode": "1F376", + "label": "sake", + "order": 3762, + "tags": ["bar", "beverage", "bottle", "cup", "drink", "restaurant"], + "unicode": "🍶" + }, + { + "group": 4, + "hexcode": "1F37E", + "label": "bottle with popping cork", + "order": 3763, + "tags": ["bar", "bottle", "cork", "drink", "popping"], + "unicode": "🍾" + }, + { + "group": 4, + "hexcode": "1F377", + "label": "wine glass", + "order": 3764, + "tags": [ + "alcohol", + "bar", + "beverage", + "booze", + "club", + "drink", + "drinking", + "drinks", + "glass", + "restaurant", + "wine" + ], + "unicode": "🍷" + }, + { + "group": 4, + "hexcode": "1F378", + "label": "cocktail glass", + "order": 3765, + "tags": [ + "alcohol", + "bar", + "booze", + "club", + "cocktail", + "drink", + "drinking", + "drinks", + "glass", + "mad", + "martini", + "men" + ], + "unicode": "🍸️" + }, + { + "group": 4, + "hexcode": "1F379", + "label": "tropical drink", + "order": 3766, + "tags": [ + "alcohol", + "bar", + "booze", + "club", + "cocktail", + "drink", + "drinking", + "drinks", + "drunk", + "mai", + "party", + "tai", + "tropical", + "tropics" + ], + "unicode": "🍹" + }, + { + "group": 4, + "hexcode": "1F37A", + "label": "beer mug", + "order": 3767, + "tags": [ + "alcohol", + "ale", + "bar", + "beer", + "booze", + "drink", + "drinking", + "drinks", + "mug", + "octoberfest", + "oktoberfest", + "pint", + "stein", + "summer" + ], + "unicode": "🍺" + }, + { + "group": 4, + "hexcode": "1F37B", + "label": "clinking beer mugs", + "order": 3768, + "tags": [ + "alcohol", + "bar", + "beer", + "booze", + "bottoms", + "cheers", + "clink", + "clinking", + "drinking", + "drinks", + "mugs" + ], + "unicode": "🍻" + }, + { + "group": 4, + "hexcode": "1F942", + "label": "clinking glasses", + "order": 3769, + "tags": ["celebrate", "clink", "clinking", "drink", "glass", "glasses"], + "unicode": "🥂" + }, + { + "group": 4, + "hexcode": "1F943", + "label": "tumbler glass", + "order": 3770, + "tags": [ + "glass", + "liquor", + "scotch", + "shot", + "tumbler", + "whiskey", + "whisky" + ], + "unicode": "🥃" + }, + { + "group": 4, + "hexcode": "1FAD7", + "label": "pouring liquid", + "order": 3771, + "tags": [ + "accident", + "drink", + "empty", + "glass", + "liquid", + "oops", + "pour", + "pouring", + "spill", + "water" + ], + "unicode": "🫗" + }, + { + "group": 4, + "hexcode": "1F964", + "label": "cup with straw", + "order": 3772, + "tags": [ + "cup", + "drink", + "juice", + "malt", + "soda", + "soft", + "straw", + "water" + ], + "unicode": "🥤" + }, + { + "group": 4, + "hexcode": "1F9CB", + "label": "bubble tea", + "order": 3773, + "tags": ["boba", "bubble", "food", "milk", "pearl", "tea"], + "unicode": "🧋" + }, + { + "group": 4, + "hexcode": "1F9C3", + "label": "beverage box", + "order": 3774, + "tags": ["beverage", "box", "juice", "straw", "sweet"], + "unicode": "🧃" + }, + { + "group": 4, + "hexcode": "1F9C9", + "label": "mate", + "order": 3775, + "tags": ["drink"], + "unicode": "🧉" + }, + { + "group": 4, + "hexcode": "1F9CA", + "label": "ice", + "order": 3776, + "tags": ["cold", "cube", "iceberg"], + "unicode": "🧊" + }, + { + "group": 4, + "hexcode": "1F962", + "label": "chopsticks", + "order": 3777, + "tags": ["hashi", "jeotgarak", "kuaizi"], + "unicode": "🥢" + }, + { + "group": 4, + "hexcode": "1F37D", + "label": "fork and knife with plate", + "order": 3779, + "tags": ["cooking", "dinner", "eat", "fork", "knife", "plate"], + "unicode": "🍽️" + }, + { + "group": 4, + "hexcode": "1F374", + "label": "fork and knife", + "order": 3780, + "tags": [ + "breakfast", + "breaky", + "cooking", + "cutlery", + "delicious", + "dinner", + "eat", + "feed", + "food", + "fork", + "hungry", + "knife", + "lunch", + "restaurant", + "yum", + "yummy" + ], + "unicode": "🍴" + }, + { + "group": 4, + "hexcode": "1F944", + "label": "spoon", + "order": 3781, + "tags": ["eat", "tableware"], + "unicode": "🥄" + }, + { + "group": 4, + "hexcode": "1F52A", + "label": "kitchen knife", + "order": 3782, + "tags": [ + "chef", + "cooking", + "hocho", + "kitchen", + "knife", + "tool", + "weapon" + ], + "unicode": "🔪" + }, + { + "group": 4, + "hexcode": "1FAD9", + "label": "jar", + "order": 3783, + "tags": [ + "condiment", + "container", + "empty", + "nothing", + "sauce", + "store" + ], + "unicode": "🫙" + }, + { + "group": 4, + "hexcode": "1F3FA", + "label": "amphora", + "order": 3784, + "tags": [ + "aquarius", + "cooking", + "drink", + "jug", + "tool", + "weapon", + "zodiac" + ], + "unicode": "🏺" + } + ] + }, + { + "name": "Activity", + "emojis": [ + { + "group": 6, + "hexcode": "1F383", + "label": "jack-o-lantern", + "order": 4052, + "tags": ["celebration", "halloween", "jack", "lantern", "pumpkin"], + "unicode": "🎃" + }, + { + "group": 6, + "hexcode": "1F384", + "label": "Christmas tree", + "order": 4053, + "tags": ["celebration", "christmas", "tree"], + "unicode": "🎄" + }, + { + "group": 6, + "hexcode": "1F386", + "label": "fireworks", + "order": 4054, + "tags": ["boom", "celebration", "entertainment", "yolo"], + "unicode": "🎆" + }, + { + "group": 6, + "hexcode": "1F387", + "label": "sparkler", + "order": 4055, + "tags": ["boom", "celebration", "fireworks", "sparkle"], + "unicode": "🎇" + }, + { + "group": 6, + "hexcode": "1F9E8", + "label": "firecracker", + "order": 4056, + "tags": [ + "dynamite", + "explosive", + "fire", + "fireworks", + "light", + "pop", + "popping", + "spark" + ], + "unicode": "🧨" + }, + { + "group": 6, + "hexcode": "2728", + "label": "sparkles", + "order": 4057, + "tags": ["*", "magic", "sparkle", "star"], + "unicode": "✨️" + }, + { + "group": 6, + "hexcode": "1F388", + "label": "balloon", + "order": 4058, + "tags": ["birthday", "celebrate", "celebration"], + "unicode": "🎈" + }, + { + "group": 6, + "hexcode": "1F389", + "label": "party popper", + "order": 4059, + "tags": [ + "awesome", + "birthday", + "celebrate", + "celebration", + "excited", + "hooray", + "party", + "popper", + "tada", + "woohoo" + ], + "unicode": "🎉" + }, + { + "group": 6, + "hexcode": "1F38A", + "label": "confetti ball", + "order": 4060, + "tags": [ + "ball", + "celebrate", + "celebration", + "confetti", + "party", + "woohoo" + ], + "unicode": "🎊" + }, + { + "group": 6, + "hexcode": "1F38B", + "label": "tanabata tree", + "order": 4061, + "tags": ["banner", "celebration", "japanese", "tanabata", "tree"], + "unicode": "🎋" + }, + { + "group": 6, + "hexcode": "1F38D", + "label": "pine decoration", + "order": 4062, + "tags": [ + "bamboo", + "celebration", + "decoration", + "japanese", + "pine", + "plant" + ], + "unicode": "🎍" + }, + { + "group": 6, + "hexcode": "1F38E", + "label": "Japanese dolls", + "order": 4063, + "tags": ["celebration", "doll", "dolls", "festival", "japanese"], + "unicode": "🎎" + }, + { + "group": 6, + "hexcode": "1F38F", + "label": "carp streamer", + "order": 4064, + "tags": ["carp", "celebration", "streamer"], + "unicode": "🎏" + }, + { + "group": 6, + "hexcode": "1F390", + "label": "wind chime", + "order": 4065, + "tags": ["bell", "celebration", "chime", "wind"], + "unicode": "🎐" + }, + { + "group": 6, + "hexcode": "1F391", + "label": "moon viewing ceremony", + "order": 4066, + "tags": ["celebration", "ceremony", "moon", "viewing"], + "unicode": "🎑" + }, + { + "group": 6, + "hexcode": "1F9E7", + "label": "red envelope", + "order": 4067, + "tags": [ + "envelope", + "gift", + "good", + "hóngbāo", + "lai", + "luck", + "money", + "red", + "see" + ], + "unicode": "🧧" + }, + { + "group": 6, + "hexcode": "1F380", + "label": "ribbon", + "order": 4068, + "tags": ["celebration"], + "unicode": "🎀" + }, + { + "group": 6, + "hexcode": "1F381", + "label": "wrapped gift", + "order": 4069, + "tags": [ + "birthday", + "bow", + "box", + "celebration", + "christmas", + "gift", + "present", + "surprise", + "wrapped" + ], + "unicode": "🎁" + }, + { + "group": 6, + "hexcode": "1F397", + "label": "reminder ribbon", + "order": 4071, + "tags": ["celebration", "reminder", "ribbon"], + "unicode": "🎗️" + }, + { + "group": 6, + "hexcode": "1F39F", + "label": "admission tickets", + "order": 4073, + "tags": ["admission", "ticket", "tickets"], + "unicode": "🎟️" + }, + { + "group": 6, + "hexcode": "1F3AB", + "label": "ticket", + "order": 4074, + "tags": ["admission", "stub"], + "unicode": "🎫" + }, + { + "group": 6, + "hexcode": "1F396", + "label": "military medal", + "order": 4076, + "tags": ["award", "celebration", "medal", "military"], + "unicode": "🎖️" + }, + { + "group": 6, + "hexcode": "1F3C6", + "label": "trophy", + "order": 4077, + "tags": [ + "champion", + "champs", + "prize", + "slay", + "sport", + "victory", + "win", + "winning" + ], + "unicode": "🏆️" + }, + { + "group": 6, + "hexcode": "1F3C5", + "label": "sports medal", + "order": 4078, + "tags": ["award", "gold", "medal", "sports", "winner"], + "unicode": "🏅" + }, + { + "group": 6, + "hexcode": "1F947", + "label": "1st place medal", + "order": 4079, + "tags": ["1st", "first", "gold", "medal", "place"], + "unicode": "🥇" + }, + { + "group": 6, + "hexcode": "1F948", + "label": "2nd place medal", + "order": 4080, + "tags": ["2nd", "medal", "place", "second", "silver"], + "unicode": "🥈" + }, + { + "group": 6, + "hexcode": "1F949", + "label": "3rd place medal", + "order": 4081, + "tags": ["3rd", "bronze", "medal", "place", "third"], + "unicode": "🥉" + }, + { + "group": 6, + "hexcode": "26BD", + "label": "soccer ball", + "order": 4082, + "tags": ["ball", "football", "futbol", "soccer", "sport"], + "unicode": "⚽️" + }, + { + "group": 6, + "hexcode": "26BE", + "label": "baseball", + "order": 4083, + "tags": ["ball", "sport"], + "unicode": "⚾️" + }, + { + "group": 6, + "hexcode": "1F94E", + "label": "softball", + "order": 4084, + "tags": ["ball", "glove", "sports", "underarm"], + "unicode": "🥎" + }, + { + "group": 6, + "hexcode": "1F3C0", + "label": "basketball", + "order": 4085, + "tags": ["ball", "hoop", "sport"], + "unicode": "🏀" + }, + { + "group": 6, + "hexcode": "1F3D0", + "label": "volleyball", + "order": 4086, + "tags": ["ball", "game"], + "unicode": "🏐" + }, + { + "group": 6, + "hexcode": "1F3C8", + "label": "american football", + "order": 4087, + "tags": ["american", "ball", "bowl", "football", "sport", "super"], + "unicode": "🏈" + }, + { + "group": 6, + "hexcode": "1F3C9", + "label": "rugby football", + "order": 4088, + "tags": ["ball", "football", "rugby", "sport"], + "unicode": "🏉" + }, + { + "group": 6, + "hexcode": "1F3BE", + "label": "tennis", + "order": 4089, + "tags": ["ball", "racquet", "sport"], + "unicode": "🎾" + }, + { + "group": 6, + "hexcode": "1F94F", + "label": "flying disc", + "order": 4090, + "tags": ["disc", "flying", "ultimate"], + "unicode": "🥏" + }, + { + "group": 6, + "hexcode": "1F3B3", + "label": "bowling", + "order": 4091, + "tags": ["ball", "game", "sport", "strike"], + "unicode": "🎳" + }, + { + "group": 6, + "hexcode": "1F3CF", + "label": "cricket game", + "order": 4092, + "tags": ["ball", "bat", "cricket", "game"], + "unicode": "🏏" + }, + { + "group": 6, + "hexcode": "1F3D1", + "label": "field hockey", + "order": 4093, + "tags": ["ball", "field", "game", "hockey", "stick"], + "unicode": "🏑" + }, + { + "group": 6, + "hexcode": "1F3D2", + "label": "ice hockey", + "order": 4094, + "tags": ["game", "hockey", "ice", "puck", "stick"], + "unicode": "🏒" + }, + { + "group": 6, + "hexcode": "1F94D", + "label": "lacrosse", + "order": 4095, + "tags": ["ball", "goal", "sports", "stick"], + "unicode": "🥍" + }, + { + "group": 6, + "hexcode": "1F3D3", + "label": "ping pong", + "order": 4096, + "tags": [ + "ball", + "bat", + "game", + "paddle", + "ping", + "pingpong", + "pong", + "table", + "tennis" + ], + "unicode": "🏓" + }, + { + "group": 6, + "hexcode": "1F3F8", + "label": "badminton", + "order": 4097, + "tags": ["birdie", "game", "racquet", "shuttlecock"], + "unicode": "🏸" + }, + { + "group": 6, + "hexcode": "1F94A", + "label": "boxing glove", + "order": 4098, + "tags": ["boxing", "glove"], + "unicode": "🥊" + }, + { + "group": 6, + "hexcode": "1F94B", + "label": "martial arts uniform", + "order": 4099, + "tags": ["arts", "judo", "karate", "martial", "taekwondo", "uniform"], + "unicode": "🥋" + }, + { + "group": 6, + "hexcode": "1F945", + "label": "goal net", + "order": 4100, + "tags": ["goal", "net"], + "unicode": "🥅" + }, + { + "group": 6, + "hexcode": "26F3", + "label": "flag in hole", + "order": 4101, + "tags": ["flag", "golf", "hole", "sport"], + "unicode": "⛳️" + }, + { + "group": 6, + "hexcode": "26F8", + "label": "ice skate", + "order": 4103, + "tags": ["ice", "skate", "skating"], + "unicode": "⛸️" + }, + { + "group": 6, + "hexcode": "1F3A3", + "label": "fishing pole", + "order": 4104, + "tags": ["entertainment", "fish", "fishing", "pole", "sport"], + "unicode": "🎣" + }, + { + "group": 6, + "hexcode": "1F93F", + "label": "diving mask", + "order": 4105, + "tags": ["diving", "mask", "scuba", "snorkeling"], + "unicode": "🤿" + }, + { + "group": 6, + "hexcode": "1F3BD", + "label": "running shirt", + "order": 4106, + "tags": ["athletics", "running", "sash", "shirt"], + "unicode": "🎽" + }, + { + "group": 6, + "hexcode": "1F3BF", + "label": "skis", + "order": 4107, + "tags": ["ski", "snow", "sport"], + "unicode": "🎿" + }, + { + "group": 6, + "hexcode": "1F6F7", + "label": "sled", + "order": 4108, + "tags": ["luge", "sledge", "sleigh", "snow", "toboggan"], + "unicode": "🛷" + }, + { + "group": 6, + "hexcode": "1F94C", + "label": "curling stone", + "order": 4109, + "tags": ["curling", "game", "rock", "stone"], + "unicode": "🥌" + }, + { + "group": 6, + "hexcode": "1F3AF", + "label": "bullseye", + "order": 4110, + "tags": [ + "bull", + "dart", + "direct", + "entertainment", + "game", + "hit", + "target" + ], + "unicode": "🎯" + }, + { + "group": 6, + "hexcode": "1FA80", + "label": "yo-yo", + "order": 4111, + "tags": ["fluctuate", "toy"], + "unicode": "🪀" + }, + { + "group": 6, + "hexcode": "1FA81", + "label": "kite", + "order": 4112, + "tags": ["fly", "soar"], + "unicode": "🪁" + }, + { + "group": 6, + "hexcode": "1F52B", + "label": "water pistol", + "order": 4113, + "tags": [ + "gun", + "handgun", + "pistol", + "revolver", + "tool", + "water", + "weapon" + ], + "unicode": "🔫" + }, + { + "group": 6, + "hexcode": "1F3B1", + "label": "pool 8 ball", + "order": 4114, + "tags": ["8", "8ball", "ball", "billiard", "eight", "game", "pool"], + "unicode": "🎱" + }, + { + "group": 6, + "hexcode": "1F52E", + "label": "crystal ball", + "order": 4115, + "tags": [ + "ball", + "crystal", + "fairy", + "fairytale", + "fantasy", + "fortune", + "future", + "magic", + "tale", + "tool" + ], + "unicode": "🔮" + }, + { + "group": 6, + "hexcode": "1FA84", + "label": "magic wand", + "order": 4116, + "tags": ["magic", "magician", "wand", "witch", "wizard"], + "unicode": "🪄" + }, + { + "group": 6, + "hexcode": "1F3AE", + "label": "video game", + "order": 4117, + "tags": ["controller", "entertainment", "game", "video"], + "unicode": "🎮️" + }, + { + "group": 6, + "hexcode": "1F579", + "label": "joystick", + "order": 4119, + "tags": ["game", "video", "videogame"], + "unicode": "🕹️" + }, + { + "group": 6, + "hexcode": "1F3B0", + "label": "slot machine", + "order": 4120, + "tags": [ + "casino", + "gamble", + "gambling", + "game", + "machine", + "slot", + "slots" + ], + "unicode": "🎰" + }, + { + "group": 6, + "hexcode": "1F3B2", + "label": "game die", + "order": 4121, + "tags": ["dice", "die", "entertainment", "game"], + "unicode": "🎲" + }, + { + "group": 6, + "hexcode": "1F9E9", + "label": "puzzle piece", + "order": 4122, + "tags": ["clue", "interlocking", "jigsaw", "piece", "puzzle"], + "unicode": "🧩" + }, + { + "group": 6, + "hexcode": "1F9F8", + "label": "teddy bear", + "order": 4123, + "tags": ["bear", "plaything", "plush", "stuffed", "teddy", "toy"], + "unicode": "🧸" + }, + { + "group": 6, + "hexcode": "1FA85", + "label": "piñata", + "order": 4124, + "tags": [ + "candy", + "celebrate", + "celebration", + "cinco", + "de", + "festive", + "mayo", + "party", + "pinada", + "pinata" + ], + "unicode": "🪅" + }, + { + "group": 6, + "hexcode": "1FAA9", + "label": "mirror ball", + "order": 4125, + "tags": ["ball", "dance", "disco", "glitter", "mirror", "party"], + "unicode": "🪩" + }, + { + "group": 6, + "hexcode": "1FA86", + "label": "nesting dolls", + "order": 4126, + "tags": [ + "babooshka", + "baboushka", + "babushka", + "doll", + "dolls", + "matryoshka", + "nesting", + "russia" + ], + "unicode": "🪆" + }, + { + "group": 6, + "hexcode": "2660", + "label": "spade suit", + "order": 4128, + "tags": ["card", "game", "spade", "suit"], + "unicode": "♠️" + }, + { + "group": 6, + "hexcode": "2665", + "label": "heart suit", + "order": 4130, + "tags": ["card", "emotion", "game", "heart", "hearts", "suit"], + "unicode": "♥️" + }, + { + "group": 6, + "hexcode": "2666", + "label": "diamond suit", + "order": 4132, + "tags": ["card", "diamond", "game", "suit"], + "unicode": "♦️" + }, + { + "group": 6, + "hexcode": "2663", + "label": "club suit", + "order": 4134, + "tags": ["card", "club", "clubs", "game", "suit"], + "unicode": "♣️" + }, + { + "group": 6, + "hexcode": "265F", + "label": "chess pawn", + "order": 4136, + "tags": ["chess", "dupe", "expendable", "pawn"], + "unicode": "♟️" + }, + { + "group": 6, + "hexcode": "1F0CF", + "label": "joker", + "order": 4137, + "tags": ["card", "game", "wildcard"], + "unicode": "🃏" + }, + { + "group": 6, + "hexcode": "1F004", + "label": "mahjong red dragon", + "order": 4138, + "tags": ["dragon", "game", "mahjong", "red"], + "unicode": "🀄️" + }, + { + "group": 6, + "hexcode": "1F3B4", + "label": "flower playing cards", + "order": 4139, + "tags": ["card", "cards", "flower", "game", "japanese", "playing"], + "unicode": "🎴" + }, + { + "group": 6, + "hexcode": "1F3AD", + "label": "performing arts", + "order": 4140, + "tags": [ + "actor", + "actress", + "art", + "arts", + "entertainment", + "mask", + "performing", + "theater", + "theatre", + "thespian" + ], + "unicode": "🎭️" + }, + { + "group": 6, + "hexcode": "1F5BC", + "label": "framed picture", + "order": 4142, + "tags": ["art", "frame", "framed", "museum", "painting", "picture"], + "unicode": "🖼️" + }, + { + "group": 6, + "hexcode": "1F3A8", + "label": "artist palette", + "order": 4143, + "tags": [ + "art", + "artist", + "artsy", + "arty", + "colorful", + "creative", + "entertainment", + "museum", + "painter", + "painting", + "palette" + ], + "unicode": "🎨" + }, + { + "group": 6, + "hexcode": "1F9F5", + "label": "thread", + "order": 4144, + "tags": ["needle", "sewing", "spool", "string"], + "unicode": "🧵" + }, + { + "group": 6, + "hexcode": "1FAA1", + "label": "sewing needle", + "order": 4145, + "tags": [ + "embroidery", + "needle", + "sew", + "sewing", + "stitches", + "sutures", + "tailoring", + "thread" + ], + "unicode": "🪡" + }, + { + "group": 6, + "hexcode": "1F9F6", + "label": "yarn", + "order": 4146, + "tags": ["ball", "crochet", "knit"], + "unicode": "🧶" + }, + { + "group": 6, + "hexcode": "1FAA2", + "label": "knot", + "order": 4147, + "tags": ["cord", "rope", "tangled", "tie", "twine", "twist"], + "unicode": "🪢" + } + ] + }, + { + "name": "Travel & Places", + "emojis": [ + { + "group": 5, + "hexcode": "1F30D", + "label": "globe showing Europe-Africa", + "order": 3785, + "tags": [ + "africa", + "earth", + "europe", + "europe-africa", + "globe", + "showing", + "world" + ], + "unicode": "🌍️" + }, + { + "group": 5, + "hexcode": "1F30E", + "label": "globe showing Americas", + "order": 3786, + "tags": ["americas", "earth", "globe", "showing", "world"], + "unicode": "🌎️" + }, + { + "group": 5, + "hexcode": "1F30F", + "label": "globe showing Asia-Australia", + "order": 3787, + "tags": [ + "asia", + "asia-australia", + "australia", + "earth", + "globe", + "showing", + "world" + ], + "unicode": "🌏️" + }, + { + "group": 5, + "hexcode": "1F310", + "label": "globe with meridians", + "order": 3788, + "tags": [ + "earth", + "globe", + "internet", + "meridians", + "web", + "world", + "worldwide" + ], + "unicode": "🌐" + }, + { + "group": 5, + "hexcode": "1F5FA", + "label": "world map", + "order": 3790, + "tags": ["map", "world"], + "unicode": "🗺️" + }, + { + "group": 5, + "hexcode": "1F5FE", + "label": "map of Japan", + "order": 3791, + "tags": ["japan", "map"], + "unicode": "🗾" + }, + { + "group": 5, + "hexcode": "1F9ED", + "label": "compass", + "order": 3792, + "tags": ["direction", "magnetic", "navigation", "orienteering"], + "unicode": "🧭" + }, + { + "group": 5, + "hexcode": "1F3D4", + "label": "snow-capped mountain", + "order": 3794, + "tags": ["cold", "mountain", "snow", "snow-capped"], + "unicode": "🏔️" + }, + { + "group": 5, + "hexcode": "26F0", + "label": "mountain", + "order": 3796, + "tags": ["mountain"], + "unicode": "⛰️" + }, + { + "group": 5, + "hexcode": "1F30B", + "label": "volcano", + "order": 3797, + "tags": ["eruption", "mountain", "nature"], + "unicode": "🌋" + }, + { + "group": 5, + "hexcode": "1F5FB", + "label": "mount fuji", + "order": 3798, + "tags": ["fuji", "mount", "mountain", "nature"], + "unicode": "🗻" + }, + { + "group": 5, + "hexcode": "1F3D5", + "label": "camping", + "order": 3800, + "tags": ["camping"], + "unicode": "🏕️" + }, + { + "group": 5, + "hexcode": "1F3D6", + "label": "beach with umbrella", + "order": 3802, + "tags": ["beach", "umbrella"], + "unicode": "🏖️" + }, + { + "group": 5, + "hexcode": "1F3DC", + "label": "desert", + "order": 3804, + "tags": ["desert"], + "unicode": "🏜️" + }, + { + "group": 5, + "hexcode": "1F3DD", + "label": "desert island", + "order": 3806, + "tags": ["desert", "island"], + "unicode": "🏝️" + }, + { + "group": 5, + "hexcode": "1F3DE", + "label": "national park", + "order": 3808, + "tags": ["national", "park"], + "unicode": "🏞️" + }, + { + "group": 5, + "hexcode": "1F3DF", + "label": "stadium", + "order": 3810, + "tags": ["stadium"], + "unicode": "🏟️" + }, + { + "group": 5, + "hexcode": "1F3DB", + "label": "classical building", + "order": 3812, + "tags": ["building", "classical"], + "unicode": "🏛️" + }, + { + "group": 5, + "hexcode": "1F3D7", + "label": "building construction", + "order": 3814, + "tags": ["building", "construction", "crane"], + "unicode": "🏗️" + }, + { + "group": 5, + "hexcode": "1F9F1", + "label": "brick", + "order": 3815, + "tags": ["bricks", "clay", "mortar", "wall"], + "unicode": "🧱" + }, + { + "group": 5, + "hexcode": "1FAA8", + "label": "rock", + "order": 3816, + "tags": ["boulder", "heavy", "solid", "stone", "tough"], + "unicode": "🪨" + }, + { + "group": 5, + "hexcode": "1FAB5", + "label": "wood", + "order": 3817, + "tags": ["log", "lumber", "timber"], + "unicode": "🪵" + }, + { + "group": 5, + "hexcode": "1F6D6", + "label": "hut", + "order": 3818, + "tags": ["home", "house", "roundhouse", "shelter", "yurt"], + "unicode": "🛖" + }, + { + "group": 5, + "hexcode": "1F3D8", + "label": "houses", + "order": 3820, + "tags": ["house"], + "unicode": "🏘️" + }, + { + "group": 5, + "hexcode": "1F3DA", + "label": "derelict house", + "order": 3822, + "tags": ["derelict", "home", "house"], + "unicode": "🏚️" + }, + { + "group": 5, + "hexcode": "1F3E0", + "label": "house", + "order": 3823, + "tags": [ + "building", + "country", + "heart", + "home", + "ranch", + "settle", + "simple", + "suburban", + "suburbia", + "where" + ], + "unicode": "🏠️" + }, + { + "group": 5, + "hexcode": "1F3E1", + "label": "house with garden", + "order": 3824, + "tags": [ + "building", + "country", + "garden", + "heart", + "home", + "house", + "ranch", + "settle", + "simple", + "suburban", + "suburbia", + "where" + ], + "unicode": "🏡" + }, + { + "group": 5, + "hexcode": "1F3E2", + "label": "office building", + "order": 3825, + "tags": ["building", "city", "cubical", "job", "office"], + "unicode": "🏢" + }, + { + "group": 5, + "hexcode": "1F3E3", + "label": "Japanese post office", + "order": 3826, + "tags": ["building", "japanese", "office", "post"], + "unicode": "🏣" + }, + { + "group": 5, + "hexcode": "1F3E4", + "label": "post office", + "order": 3827, + "tags": ["building", "european", "office", "post"], + "unicode": "🏤" + }, + { + "group": 5, + "hexcode": "1F3E5", + "label": "hospital", + "order": 3828, + "tags": ["building", "doctor", "medicine"], + "unicode": "🏥" + }, + { + "group": 5, + "hexcode": "1F3E6", + "label": "bank", + "order": 3829, + "tags": ["building"], + "unicode": "🏦" + }, + { + "group": 5, + "hexcode": "1F3E8", + "label": "hotel", + "order": 3830, + "tags": ["building"], + "unicode": "🏨" + }, + { + "group": 5, + "hexcode": "1F3E9", + "label": "love hotel", + "order": 3831, + "tags": ["building", "hotel", "love"], + "unicode": "🏩" + }, + { + "group": 5, + "hexcode": "1F3EA", + "label": "convenience store", + "order": 3832, + "tags": ["24", "building", "convenience", "hours", "store"], + "unicode": "🏪" + }, + { + "group": 5, + "hexcode": "1F3EB", + "label": "school", + "order": 3833, + "tags": ["building"], + "unicode": "🏫" + }, + { + "group": 5, + "hexcode": "1F3EC", + "label": "department store", + "order": 3834, + "tags": ["building", "department", "store"], + "unicode": "🏬" + }, + { + "group": 5, + "hexcode": "1F3ED", + "label": "factory", + "order": 3835, + "tags": ["building"], + "unicode": "🏭️" + }, + { + "group": 5, + "hexcode": "1F3EF", + "label": "Japanese castle", + "order": 3836, + "tags": ["building", "castle", "japanese"], + "unicode": "🏯" + }, + { + "group": 5, + "hexcode": "1F3F0", + "label": "castle", + "order": 3837, + "tags": ["building", "european"], + "unicode": "🏰" + }, + { + "group": 5, + "hexcode": "1F492", + "label": "wedding", + "order": 3838, + "tags": ["chapel", "hitched", "nuptials", "romance"], + "unicode": "💒" + }, + { + "group": 5, + "hexcode": "1F5FC", + "label": "Tokyo tower", + "order": 3839, + "tags": ["tokyo", "tower"], + "unicode": "🗼" + }, + { + "group": 5, + "hexcode": "1F5FD", + "label": "Statue of Liberty", + "order": 3840, + "tags": ["liberty", "new", "ny", "nyc", "statue", "york"], + "unicode": "🗽" + }, + { + "group": 5, + "hexcode": "26EA", + "label": "church", + "order": 3841, + "tags": ["bless", "chapel", "christian", "cross", "religion"], + "unicode": "⛪️" + }, + { + "group": 5, + "hexcode": "1F54C", + "label": "mosque", + "order": 3842, + "tags": ["islam", "masjid", "muslim", "religion"], + "unicode": "🕌" + }, + { + "group": 5, + "hexcode": "1F6D5", + "label": "hindu temple", + "order": 3843, + "tags": ["hindu", "temple"], + "unicode": "🛕" + }, + { + "group": 5, + "hexcode": "1F54D", + "label": "synagogue", + "order": 3844, + "tags": ["jew", "jewish", "judaism", "religion", "temple"], + "unicode": "🕍" + }, + { + "group": 5, + "hexcode": "26E9", + "label": "shinto shrine", + "order": 3846, + "tags": ["religion", "shinto", "shrine"], + "unicode": "⛩️" + }, + { + "group": 5, + "hexcode": "1F54B", + "label": "kaaba", + "order": 3847, + "tags": ["hajj", "islam", "muslim", "religion", "umrah"], + "unicode": "🕋" + }, + { + "group": 5, + "hexcode": "26F2", + "label": "fountain", + "order": 3848, + "tags": ["fountain"], + "unicode": "⛲️" + }, + { + "group": 5, + "hexcode": "26FA", + "label": "tent", + "order": 3849, + "tags": ["camping"], + "unicode": "⛺️" + }, + { + "group": 5, + "hexcode": "1F301", + "label": "foggy", + "order": 3850, + "tags": ["fog"], + "unicode": "🌁" + }, + { + "group": 5, + "hexcode": "1F303", + "label": "night with stars", + "order": 3851, + "tags": ["night", "star", "stars"], + "unicode": "🌃" + }, + { + "group": 5, + "hexcode": "1F3D9", + "label": "cityscape", + "order": 3853, + "tags": ["city"], + "unicode": "🏙️" + }, + { + "group": 5, + "hexcode": "1F304", + "label": "sunrise over mountains", + "order": 3854, + "tags": ["morning", "mountains", "over", "sun", "sunrise"], + "unicode": "🌄" + }, + { + "group": 5, + "hexcode": "1F305", + "label": "sunrise", + "order": 3855, + "tags": ["morning", "nature", "sun"], + "unicode": "🌅" + }, + { + "group": 5, + "hexcode": "1F306", + "label": "cityscape at dusk", + "order": 3856, + "tags": [ + "at", + "building", + "city", + "cityscape", + "dusk", + "evening", + "landscape", + "sun", + "sunset" + ], + "unicode": "🌆" + }, + { + "group": 5, + "hexcode": "1F307", + "label": "sunset", + "order": 3857, + "tags": ["building", "dusk", "sun"], + "unicode": "🌇" + }, + { + "group": 5, + "hexcode": "1F309", + "label": "bridge at night", + "order": 3858, + "tags": ["at", "bridge", "night"], + "unicode": "🌉" + }, + { + "group": 5, + "hexcode": "2668", + "label": "hot springs", + "order": 3860, + "tags": ["hot", "hotsprings", "springs", "steaming"], + "unicode": "♨️" + }, + { + "group": 5, + "hexcode": "1F3A0", + "label": "carousel horse", + "order": 3861, + "tags": ["carousel", "entertainment", "horse"], + "unicode": "🎠" + }, + { + "group": 5, + "hexcode": "1F6DD", + "label": "playground slide", + "order": 3862, + "tags": [ + "amusement", + "park", + "play", + "playground", + "playing", + "slide", + "sliding", + "theme" + ], + "unicode": "🛝" + }, + { + "group": 5, + "hexcode": "1F3A1", + "label": "ferris wheel", + "order": 3863, + "tags": ["amusement", "ferris", "park", "theme", "wheel"], + "unicode": "🎡" + }, + { + "group": 5, + "hexcode": "1F3A2", + "label": "roller coaster", + "order": 3864, + "tags": ["amusement", "coaster", "park", "roller", "theme"], + "unicode": "🎢" + }, + { + "group": 5, + "hexcode": "1F488", + "label": "barber pole", + "order": 3865, + "tags": ["barber", "cut", "fresh", "haircut", "pole", "shave"], + "unicode": "💈" + }, + { + "group": 5, + "hexcode": "1F3AA", + "label": "circus tent", + "order": 3866, + "tags": ["circus", "tent"], + "unicode": "🎪" + }, + { + "group": 5, + "hexcode": "1F682", + "label": "locomotive", + "order": 3867, + "tags": [ + "caboose", + "engine", + "railway", + "steam", + "train", + "trains", + "travel" + ], + "unicode": "🚂" + }, + { + "group": 5, + "hexcode": "1F683", + "label": "railway car", + "order": 3868, + "tags": [ + "car", + "electric", + "railway", + "train", + "tram", + "travel", + "trolleybus" + ], + "unicode": "🚃" + }, + { + "group": 5, + "hexcode": "1F684", + "label": "high-speed train", + "order": 3869, + "tags": ["high-speed", "railway", "shinkansen", "speed", "train"], + "unicode": "🚄" + }, + { + "group": 5, + "hexcode": "1F685", + "label": "bullet train", + "order": 3870, + "tags": [ + "bullet", + "high-speed", + "nose", + "railway", + "shinkansen", + "speed", + "train", + "travel" + ], + "unicode": "🚅" + }, + { + "group": 5, + "hexcode": "1F686", + "label": "train", + "order": 3871, + "tags": ["arrived", "choo", "railway"], + "unicode": "🚆" + }, + { + "group": 5, + "hexcode": "1F687", + "label": "metro", + "order": 3872, + "tags": ["subway", "travel"], + "unicode": "🚇️" + }, + { + "group": 5, + "hexcode": "1F688", + "label": "light rail", + "order": 3873, + "tags": ["arrived", "light", "monorail", "rail", "railway"], + "unicode": "🚈" + }, + { + "group": 5, + "hexcode": "1F689", + "label": "station", + "order": 3874, + "tags": ["railway", "train"], + "unicode": "🚉" + }, + { + "group": 5, + "hexcode": "1F68A", + "label": "tram", + "order": 3875, + "tags": ["trolleybus"], + "unicode": "🚊" + }, + { + "group": 5, + "hexcode": "1F69D", + "label": "monorail", + "order": 3876, + "tags": ["vehicle"], + "unicode": "🚝" + }, + { + "group": 5, + "hexcode": "1F69E", + "label": "mountain railway", + "order": 3877, + "tags": ["car", "mountain", "railway", "trip"], + "unicode": "🚞" + }, + { + "group": 5, + "hexcode": "1F68B", + "label": "tram car", + "order": 3878, + "tags": ["bus", "car", "tram", "trolley", "trolleybus"], + "unicode": "🚋" + }, + { + "group": 5, + "hexcode": "1F68C", + "label": "bus", + "order": 3879, + "tags": ["school", "vehicle"], + "unicode": "🚌" + }, + { + "group": 5, + "hexcode": "1F68D", + "label": "oncoming bus", + "order": 3880, + "tags": ["bus", "cars", "oncoming"], + "unicode": "🚍️" + }, + { + "group": 5, + "hexcode": "1F68E", + "label": "trolleybus", + "order": 3881, + "tags": ["bus", "tram", "trolley"], + "unicode": "🚎" + }, + { + "group": 5, + "hexcode": "1F690", + "label": "minibus", + "order": 3882, + "tags": ["bus", "drive", "van", "vehicle"], + "unicode": "🚐" + }, + { + "group": 5, + "hexcode": "1F691", + "label": "ambulance", + "order": 3883, + "tags": ["emergency", "vehicle"], + "unicode": "🚑️" + }, + { + "group": 5, + "hexcode": "1F692", + "label": "fire engine", + "order": 3884, + "tags": ["engine", "fire", "truck"], + "unicode": "🚒" + }, + { + "group": 5, + "hexcode": "1F693", + "label": "police car", + "order": 3885, + "tags": ["5–0", "car", "cops", "patrol", "police"], + "unicode": "🚓" + }, + { + "group": 5, + "hexcode": "1F694", + "label": "oncoming police car", + "order": 3886, + "tags": ["car", "oncoming", "police"], + "unicode": "🚔️" + }, + { + "group": 5, + "hexcode": "1F695", + "label": "taxi", + "order": 3887, + "tags": ["cab", "cabbie", "car", "drive", "vehicle", "yellow"], + "unicode": "🚕" + }, + { + "group": 5, + "hexcode": "1F696", + "label": "oncoming taxi", + "order": 3888, + "tags": [ + "cab", + "cabbie", + "cars", + "drove", + "hail", + "oncoming", + "taxi", + "yellow" + ], + "unicode": "🚖" + }, + { + "group": 5, + "hexcode": "1F697", + "label": "automobile", + "order": 3889, + "tags": ["car", "driving", "vehicle"], + "unicode": "🚗" + }, + { + "group": 5, + "hexcode": "1F698", + "label": "oncoming automobile", + "order": 3890, + "tags": ["automobile", "car", "cars", "drove", "oncoming", "vehicle"], + "unicode": "🚘️" + }, + { + "group": 5, + "hexcode": "1F699", + "label": "sport utility vehicle", + "order": 3891, + "tags": [ + "car", + "drive", + "recreational", + "sport", + "sportutility", + "utility", + "vehicle" + ], + "unicode": "🚙" + }, + { + "group": 5, + "hexcode": "1F6FB", + "label": "pickup truck", + "order": 3892, + "tags": [ + "automobile", + "car", + "flatbed", + "pick-up", + "pickup", + "transportation", + "truck" + ], + "unicode": "🛻" + }, + { + "group": 5, + "hexcode": "1F69A", + "label": "delivery truck", + "order": 3893, + "tags": ["car", "delivery", "drive", "truck", "vehicle"], + "unicode": "🚚" + }, + { + "group": 5, + "hexcode": "1F69B", + "label": "articulated lorry", + "order": 3894, + "tags": [ + "articulated", + "car", + "drive", + "lorry", + "move", + "semi", + "truck", + "vehicle" + ], + "unicode": "🚛" + }, + { + "group": 5, + "hexcode": "1F69C", + "label": "tractor", + "order": 3895, + "tags": ["vehicle"], + "unicode": "🚜" + }, + { + "group": 5, + "hexcode": "1F3CE", + "label": "racing car", + "order": 3897, + "tags": ["car", "racing", "zoom"], + "unicode": "🏎️" + }, + { + "group": 5, + "hexcode": "1F3CD", + "label": "motorcycle", + "order": 3899, + "tags": ["racing"], + "unicode": "🏍️" + }, + { + "group": 5, + "hexcode": "1F6F5", + "label": "motor scooter", + "order": 3900, + "tags": ["motor", "scooter"], + "unicode": "🛵" + }, + { + "group": 5, + "hexcode": "1F9BD", + "label": "manual wheelchair", + "order": 3901, + "tags": ["accessibility", "manual", "wheelchair"], + "unicode": "🦽" + }, + { + "group": 5, + "hexcode": "1F9BC", + "label": "motorized wheelchair", + "order": 3902, + "tags": ["accessibility", "motorized", "wheelchair"], + "unicode": "🦼" + }, + { + "group": 5, + "hexcode": "1F6FA", + "label": "auto rickshaw", + "order": 3903, + "tags": ["auto", "rickshaw", "tuk"], + "unicode": "🛺" + }, + { + "group": 5, + "hexcode": "1F6B2", + "label": "bicycle", + "order": 3904, + "tags": [ + "bike", + "class", + "cycle", + "cycling", + "cyclist", + "gang", + "ride", + "spin", + "spinning" + ], + "unicode": "🚲️" + }, + { + "group": 5, + "hexcode": "1F6F4", + "label": "kick scooter", + "order": 3905, + "tags": ["kick", "scooter"], + "unicode": "🛴" + }, + { + "group": 5, + "hexcode": "1F6F9", + "label": "skateboard", + "order": 3906, + "tags": ["board", "skate", "skater", "wheels"], + "unicode": "🛹" + }, + { + "group": 5, + "hexcode": "1F6FC", + "label": "roller skate", + "order": 3907, + "tags": ["blades", "roller", "skate", "skates", "sport"], + "unicode": "🛼" + }, + { + "group": 5, + "hexcode": "1F68F", + "label": "bus stop", + "order": 3908, + "tags": ["bus", "busstop", "stop"], + "unicode": "🚏" + }, + { + "group": 5, + "hexcode": "1F6E3", + "label": "motorway", + "order": 3910, + "tags": ["highway", "road"], + "unicode": "🛣️" + }, + { + "group": 5, + "hexcode": "1F6E4", + "label": "railway track", + "order": 3912, + "tags": ["railway", "track", "train"], + "unicode": "🛤️" + }, + { + "group": 5, + "hexcode": "1F6E2", + "label": "oil drum", + "order": 3914, + "tags": ["drum", "oil"], + "unicode": "🛢️" + }, + { + "group": 5, + "hexcode": "26FD", + "label": "fuel pump", + "order": 3915, + "tags": [ + "diesel", + "fuel", + "fuelpump", + "gas", + "gasoline", + "pump", + "station" + ], + "unicode": "⛽️" + }, + { + "group": 5, + "hexcode": "1F6DE", + "label": "wheel", + "order": 3916, + "tags": ["car", "circle", "tire", "turn", "vehicle"], + "unicode": "🛞" + }, + { + "group": 5, + "hexcode": "1F6A8", + "label": "police car light", + "order": 3917, + "tags": [ + "alarm", + "alert", + "beacon", + "car", + "emergency", + "light", + "police", + "revolving", + "siren" + ], + "unicode": "🚨" + }, + { + "group": 5, + "hexcode": "1F6A5", + "label": "horizontal traffic light", + "order": 3918, + "tags": [ + "horizontal", + "intersection", + "light", + "signal", + "stop", + "stoplight", + "traffic" + ], + "unicode": "🚥" + }, + { + "group": 5, + "hexcode": "1F6A6", + "label": "vertical traffic light", + "order": 3919, + "tags": [ + "drove", + "intersection", + "light", + "signal", + "stop", + "stoplight", + "traffic", + "vertical" + ], + "unicode": "🚦" + }, + { + "group": 5, + "hexcode": "1F6D1", + "label": "stop sign", + "order": 3920, + "tags": ["octagonal", "sign", "stop"], + "unicode": "🛑" + }, + { + "group": 5, + "hexcode": "1F6A7", + "label": "construction", + "order": 3921, + "tags": ["barrier"], + "unicode": "🚧" + }, + { + "group": 5, + "hexcode": "2693", + "label": "anchor", + "order": 3922, + "tags": ["ship", "tool"], + "unicode": "⚓️" + }, + { + "group": 5, + "hexcode": "1F6DF", + "label": "ring buoy", + "order": 3923, + "tags": [ + "buoy", + "float", + "life", + "lifesaver", + "preserver", + "rescue", + "ring", + "safety", + "save", + "saver", + "swim" + ], + "unicode": "🛟" + }, + { + "group": 5, + "hexcode": "26F5", + "label": "sailboat", + "order": 3924, + "tags": ["boat", "resort", "sailing", "sea", "yacht"], + "unicode": "⛵️" + }, + { + "group": 5, + "hexcode": "1F6F6", + "label": "canoe", + "order": 3925, + "tags": ["boat"], + "unicode": "🛶" + }, + { + "group": 5, + "hexcode": "1F6A4", + "label": "speedboat", + "order": 3926, + "tags": [ + "billionaire", + "boat", + "lake", + "luxury", + "millionaire", + "summer", + "travel" + ], + "unicode": "🚤" + }, + { + "group": 5, + "hexcode": "1F6F3", + "label": "passenger ship", + "order": 3928, + "tags": ["passenger", "ship"], + "unicode": "🛳️" + }, + { + "group": 5, + "hexcode": "26F4", + "label": "ferry", + "order": 3930, + "tags": ["boat", "passenger"], + "unicode": "⛴️" + }, + { + "group": 5, + "hexcode": "1F6E5", + "label": "motor boat", + "order": 3932, + "tags": ["boat", "motor", "motorboat"], + "unicode": "🛥️" + }, + { + "group": 5, + "hexcode": "1F6A2", + "label": "ship", + "order": 3933, + "tags": ["boat", "passenger", "travel"], + "unicode": "🚢" + }, + { + "group": 5, + "hexcode": "2708", + "label": "airplane", + "order": 3935, + "tags": ["aeroplane", "fly", "flying", "jet", "plane", "travel"], + "unicode": "✈️" + }, + { + "group": 5, + "hexcode": "1F6E9", + "label": "small airplane", + "order": 3937, + "tags": ["aeroplane", "airplane", "plane", "small"], + "unicode": "🛩️" + }, + { + "group": 5, + "hexcode": "1F6EB", + "label": "airplane departure", + "order": 3938, + "tags": [ + "aeroplane", + "airplane", + "check-in", + "departure", + "departures", + "plane" + ], + "unicode": "🛫" + }, + { + "group": 5, + "hexcode": "1F6EC", + "label": "airplane arrival", + "order": 3939, + "tags": [ + "aeroplane", + "airplane", + "arrival", + "arrivals", + "arriving", + "landing", + "plane" + ], + "unicode": "🛬" + }, + { + "group": 5, + "hexcode": "1FA82", + "label": "parachute", + "order": 3940, + "tags": ["hang-glide", "parasail", "skydive"], + "unicode": "🪂" + }, + { + "group": 5, + "hexcode": "1F4BA", + "label": "seat", + "order": 3941, + "tags": ["chair"], + "unicode": "💺" + }, + { + "group": 5, + "hexcode": "1F681", + "label": "helicopter", + "order": 3942, + "tags": ["copter", "roflcopter", "travel", "vehicle"], + "unicode": "🚁" + }, + { + "group": 5, + "hexcode": "1F69F", + "label": "suspension railway", + "order": 3943, + "tags": ["railway", "suspension"], + "unicode": "🚟" + }, + { + "group": 5, + "hexcode": "1F6A0", + "label": "mountain cableway", + "order": 3944, + "tags": ["cable", "cableway", "gondola", "lift", "mountain", "ski"], + "unicode": "🚠" + }, + { + "group": 5, + "hexcode": "1F6A1", + "label": "aerial tramway", + "order": 3945, + "tags": ["aerial", "cable", "car", "gondola", "ropeway", "tramway"], + "unicode": "🚡" + }, + { + "group": 5, + "hexcode": "1F6F0", + "label": "satellite", + "order": 3947, + "tags": ["space"], + "unicode": "🛰️" + }, + { + "group": 5, + "hexcode": "1F680", + "label": "rocket", + "order": 3948, + "tags": ["launch", "rockets", "space", "travel"], + "unicode": "🚀" + }, + { + "group": 5, + "hexcode": "1F6F8", + "label": "flying saucer", + "order": 3949, + "tags": ["aliens", "extra", "flying", "saucer", "terrestrial", "ufo"], + "unicode": "🛸" + }, + { + "group": 5, + "hexcode": "1F6CE", + "label": "bellhop bell", + "order": 3951, + "tags": ["bell", "bellhop", "hotel"], + "unicode": "🛎️" + }, + { + "group": 5, + "hexcode": "1F9F3", + "label": "luggage", + "order": 3952, + "tags": ["bag", "packing", "roller", "suitcase", "travel"], + "unicode": "🧳" + }, + { + "group": 5, + "hexcode": "231B", + "label": "hourglass done", + "order": 3953, + "tags": ["done", "hourglass", "sand", "time", "timer"], + "unicode": "⌛️" + }, + { + "group": 5, + "hexcode": "23F3", + "label": "hourglass not done", + "order": 3954, + "tags": [ + "done", + "flowing", + "hourglass", + "hours", + "not", + "sand", + "timer", + "waiting", + "yolo" + ], + "unicode": "⏳️" + }, + { + "group": 5, + "hexcode": "231A", + "label": "watch", + "order": 3955, + "tags": ["clock", "time"], + "unicode": "⌚️" + }, + { + "group": 5, + "hexcode": "23F0", + "label": "alarm clock", + "order": 3956, + "tags": ["alarm", "clock", "hours", "hrs", "late", "time", "waiting"], + "unicode": "⏰️" + }, + { + "group": 5, + "hexcode": "23F1", + "label": "stopwatch", + "order": 3958, + "tags": ["clock", "time"], + "unicode": "⏱️" + }, + { + "group": 5, + "hexcode": "23F2", + "label": "timer clock", + "order": 3960, + "tags": ["clock", "timer"], + "unicode": "⏲️" + }, + { + "group": 5, + "hexcode": "1F570", + "label": "mantelpiece clock", + "order": 3962, + "tags": ["clock", "mantelpiece", "time"], + "unicode": "🕰️" + }, + { + "group": 5, + "hexcode": "1F55B", + "label": "twelve o’clock", + "order": 3963, + "tags": ["12", "12:00", "clock", "o’clock", "time", "twelve"], + "unicode": "🕛️" + }, + { + "group": 5, + "hexcode": "1F567", + "label": "twelve-thirty", + "order": 3964, + "tags": ["12", "12:30", "30", "clock", "thirty", "time", "twelve"], + "unicode": "🕧️" + }, + { + "group": 5, + "hexcode": "1F550", + "label": "one o’clock", + "order": 3965, + "tags": ["1", "1:00", "clock", "one", "o’clock", "time"], + "unicode": "🕐️" + }, + { + "group": 5, + "hexcode": "1F55C", + "label": "one-thirty", + "order": 3966, + "tags": ["1", "1:30", "30", "clock", "one", "thirty", "time"], + "unicode": "🕜️" + }, + { + "group": 5, + "hexcode": "1F551", + "label": "two o’clock", + "order": 3967, + "tags": ["2", "2:00", "clock", "o’clock", "time", "two"], + "unicode": "🕑️" + }, + { + "group": 5, + "hexcode": "1F55D", + "label": "two-thirty", + "order": 3968, + "tags": ["2", "2:30", "30", "clock", "thirty", "time", "two"], + "unicode": "🕝️" + }, + { + "group": 5, + "hexcode": "1F552", + "label": "three o’clock", + "order": 3969, + "tags": ["3", "3:00", "clock", "o’clock", "three", "time"], + "unicode": "🕒️" + }, + { + "group": 5, + "hexcode": "1F55E", + "label": "three-thirty", + "order": 3970, + "tags": ["3", "30", "3:30", "clock", "thirty", "three", "time"], + "unicode": "🕞️" + }, + { + "group": 5, + "hexcode": "1F553", + "label": "four o’clock", + "order": 3971, + "tags": ["4", "4:00", "clock", "four", "o’clock", "time"], + "unicode": "🕓️" + }, + { + "group": 5, + "hexcode": "1F55F", + "label": "four-thirty", + "order": 3972, + "tags": ["30", "4", "4:30", "clock", "four", "thirty", "time"], + "unicode": "🕟️" + }, + { + "group": 5, + "hexcode": "1F554", + "label": "five o’clock", + "order": 3973, + "tags": ["5", "5:00", "clock", "five", "o’clock", "time"], + "unicode": "🕔️" + }, + { + "group": 5, + "hexcode": "1F560", + "label": "five-thirty", + "order": 3974, + "tags": ["30", "5", "5:30", "clock", "five", "thirty", "time"], + "unicode": "🕠️" + }, + { + "group": 5, + "hexcode": "1F555", + "label": "six o’clock", + "order": 3975, + "tags": ["6", "6:00", "clock", "o’clock", "six", "time"], + "unicode": "🕕️" + }, + { + "group": 5, + "hexcode": "1F561", + "label": "six-thirty", + "order": 3976, + "tags": ["30", "6", "6:30", "clock", "six", "thirty"], + "unicode": "🕡️" + }, + { + "group": 5, + "hexcode": "1F556", + "label": "seven o’clock", + "order": 3977, + "tags": ["0", "7", "7:00", "clock", "o’clock", "seven"], + "unicode": "🕖️" + }, + { + "group": 5, + "hexcode": "1F562", + "label": "seven-thirty", + "order": 3978, + "tags": ["30", "7", "7:30", "clock", "seven", "thirty"], + "unicode": "🕢️" + }, + { + "group": 5, + "hexcode": "1F557", + "label": "eight o’clock", + "order": 3979, + "tags": ["8", "8:00", "clock", "eight", "o’clock", "time"], + "unicode": "🕗️" + }, + { + "group": 5, + "hexcode": "1F563", + "label": "eight-thirty", + "order": 3980, + "tags": ["30", "8", "8:30", "clock", "eight", "thirty", "time"], + "unicode": "🕣️" + }, + { + "group": 5, + "hexcode": "1F558", + "label": "nine o’clock", + "order": 3981, + "tags": ["9", "9:00", "clock", "nine", "o’clock", "time"], + "unicode": "🕘️" + }, + { + "group": 5, + "hexcode": "1F564", + "label": "nine-thirty", + "order": 3982, + "tags": ["30", "9", "9:30", "clock", "nine", "thirty", "time"], + "unicode": "🕤️" + }, + { + "group": 5, + "hexcode": "1F559", + "label": "ten o’clock", + "order": 3983, + "tags": ["0", "10", "10:00", "clock", "o’clock", "ten"], + "unicode": "🕙️" + }, + { + "group": 5, + "hexcode": "1F565", + "label": "ten-thirty", + "order": 3984, + "tags": ["10", "10:30", "30", "clock", "ten", "thirty", "time"], + "unicode": "🕥️" + }, + { + "group": 5, + "hexcode": "1F55A", + "label": "eleven o’clock", + "order": 3985, + "tags": ["11", "11:00", "clock", "eleven", "o’clock", "time"], + "unicode": "🕚️" + }, + { + "group": 5, + "hexcode": "1F566", + "label": "eleven-thirty", + "order": 3986, + "tags": ["11", "11:30", "30", "clock", "eleven", "thirty", "time"], + "unicode": "🕦️" + }, + { + "group": 5, + "hexcode": "1F311", + "label": "new moon", + "order": 3987, + "tags": ["dark", "moon", "new", "space"], + "unicode": "🌑" + }, + { + "group": 5, + "hexcode": "1F312", + "label": "waxing crescent moon", + "order": 3988, + "tags": ["crescent", "dreams", "moon", "space", "waxing"], + "unicode": "🌒" + }, + { + "group": 5, + "hexcode": "1F313", + "label": "first quarter moon", + "order": 3989, + "tags": ["first", "moon", "quarter", "space"], + "unicode": "🌓" + }, + { + "group": 5, + "hexcode": "1F314", + "label": "waxing gibbous moon", + "order": 3990, + "tags": ["gibbous", "moon", "space", "waxing"], + "unicode": "🌔" + }, + { + "group": 5, + "hexcode": "1F315", + "label": "full moon", + "order": 3991, + "tags": ["full", "moon", "space"], + "unicode": "🌕️" + }, + { + "group": 5, + "hexcode": "1F316", + "label": "waning gibbous moon", + "order": 3992, + "tags": ["gibbous", "moon", "space", "waning"], + "unicode": "🌖" + }, + { + "group": 5, + "hexcode": "1F317", + "label": "last quarter moon", + "order": 3993, + "tags": ["last", "moon", "quarter", "space"], + "unicode": "🌗" + }, + { + "group": 5, + "hexcode": "1F318", + "label": "waning crescent moon", + "order": 3994, + "tags": ["crescent", "moon", "space", "waning"], + "unicode": "🌘" + }, + { + "group": 5, + "hexcode": "1F319", + "label": "crescent moon", + "order": 3995, + "tags": ["crescent", "moon", "ramadan", "space"], + "unicode": "🌙" + }, + { + "group": 5, + "hexcode": "1F31A", + "label": "new moon face", + "order": 3996, + "tags": ["face", "moon", "new", "space"], + "unicode": "🌚" + }, + { + "group": 5, + "hexcode": "1F31B", + "label": "first quarter moon face", + "order": 3997, + "tags": ["face", "first", "moon", "quarter", "space"], + "unicode": "🌛" + }, + { + "group": 5, + "hexcode": "1F31C", + "label": "last quarter moon face", + "order": 3998, + "tags": ["dreams", "face", "last", "moon", "quarter"], + "unicode": "🌜️" + }, + { + "group": 5, + "hexcode": "1F321", + "label": "thermometer", + "order": 4000, + "tags": ["weather"], + "unicode": "🌡️" + }, + { + "group": 5, + "hexcode": "2600", + "label": "sun", + "order": 4002, + "tags": ["bright", "rays", "space", "sunny", "weather"], + "unicode": "☀️" + }, + { + "group": 5, + "hexcode": "1F31D", + "label": "full moon face", + "order": 4003, + "tags": ["bright", "face", "full", "moon"], + "unicode": "🌝" + }, + { + "group": 5, + "hexcode": "1F31E", + "label": "sun with face", + "order": 4004, + "tags": [ + "beach", + "bright", + "day", + "face", + "heat", + "shine", + "sun", + "sunny", + "sunshine", + "weather" + ], + "unicode": "🌞" + }, + { + "group": 5, + "hexcode": "1FA90", + "label": "ringed planet", + "order": 4005, + "tags": ["planet", "ringed", "saturn", "saturnine"], + "unicode": "🪐" + }, + { + "group": 5, + "hexcode": "2B50", + "label": "star", + "order": 4006, + "tags": ["astronomy", "medium", "stars", "white"], + "unicode": "⭐️" + }, + { + "group": 5, + "hexcode": "1F31F", + "label": "glowing star", + "order": 4007, + "tags": [ + "glittery", + "glow", + "glowing", + "night", + "shining", + "sparkle", + "star", + "win" + ], + "unicode": "🌟" + }, + { + "group": 5, + "hexcode": "1F320", + "label": "shooting star", + "order": 4008, + "tags": ["falling", "night", "shooting", "space", "star"], + "unicode": "🌠" + }, + { + "group": 5, + "hexcode": "1F30C", + "label": "milky way", + "order": 4009, + "tags": ["milky", "space", "way"], + "unicode": "🌌" + }, + { + "group": 5, + "hexcode": "2601", + "label": "cloud", + "order": 4011, + "tags": ["weather"], + "unicode": "☁️" + }, + { + "group": 5, + "hexcode": "26C5", + "label": "sun behind cloud", + "order": 4012, + "tags": ["behind", "cloud", "cloudy", "sun", "weather"], + "unicode": "⛅️" + }, + { + "group": 5, + "hexcode": "26C8", + "label": "cloud with lightning and rain", + "order": 4014, + "tags": ["cloud", "lightning", "rain", "thunder", "thunderstorm"], + "unicode": "⛈️" + }, + { + "group": 5, + "hexcode": "1F324", + "label": "sun behind small cloud", + "order": 4016, + "tags": ["behind", "cloud", "sun", "weather"], + "unicode": "🌤️" + }, + { + "group": 5, + "hexcode": "1F325", + "label": "sun behind large cloud", + "order": 4018, + "tags": ["behind", "cloud", "sun", "weather"], + "unicode": "🌥️" + }, + { + "group": 5, + "hexcode": "1F326", + "label": "sun behind rain cloud", + "order": 4020, + "tags": ["behind", "cloud", "rain", "sun", "weather"], + "unicode": "🌦️" + }, + { + "group": 5, + "hexcode": "1F327", + "label": "cloud with rain", + "order": 4022, + "tags": ["cloud", "rain", "weather"], + "unicode": "🌧️" + }, + { + "group": 5, + "hexcode": "1F328", + "label": "cloud with snow", + "order": 4024, + "tags": ["cloud", "cold", "snow", "weather"], + "unicode": "🌨️" + }, + { + "group": 5, + "hexcode": "1F329", + "label": "cloud with lightning", + "order": 4026, + "tags": ["cloud", "lightning", "weather"], + "unicode": "🌩️" + }, + { + "group": 5, + "hexcode": "1F32A", + "label": "tornado", + "order": 4028, + "tags": ["cloud", "weather", "whirlwind"], + "unicode": "🌪️" + }, + { + "group": 5, + "hexcode": "1F32B", + "label": "fog", + "order": 4030, + "tags": ["cloud", "weather"], + "unicode": "🌫️" + }, + { + "group": 5, + "hexcode": "1F32C", + "label": "wind face", + "order": 4032, + "tags": ["blow", "cloud", "face", "wind"], + "unicode": "🌬️" + }, + { + "group": 5, + "hexcode": "1F300", + "label": "cyclone", + "order": 4033, + "tags": ["dizzy", "hurricane", "twister", "typhoon", "weather"], + "unicode": "🌀" + }, + { + "group": 5, + "hexcode": "1F308", + "label": "rainbow", + "order": 4034, + "tags": [ + "gay", + "genderqueer", + "glbt", + "glbtq", + "lesbian", + "lgbt", + "lgbtq", + "lgbtqia", + "nature", + "pride", + "queer", + "rain", + "trans", + "transgender", + "weather" + ], + "unicode": "🌈" + }, + { + "group": 5, + "hexcode": "1F302", + "label": "closed umbrella", + "order": 4035, + "tags": ["closed", "clothing", "rain", "umbrella"], + "unicode": "🌂" + }, + { + "group": 5, + "hexcode": "2602", + "label": "umbrella", + "order": 4037, + "tags": ["clothing", "rain"], + "unicode": "☂️" + }, + { + "group": 5, + "hexcode": "2614", + "label": "umbrella with rain drops", + "order": 4038, + "tags": ["clothing", "drop", "drops", "rain", "umbrella", "weather"], + "unicode": "☔️" + }, + { + "group": 5, + "hexcode": "26F1", + "label": "umbrella on ground", + "order": 4040, + "tags": ["ground", "rain", "sun", "umbrella"], + "unicode": "⛱️" + }, + { + "group": 5, + "hexcode": "26A1", + "label": "high voltage", + "order": 4041, + "tags": [ + "danger", + "electric", + "electricity", + "high", + "lightning", + "nature", + "thunder", + "thunderbolt", + "voltage", + "zap" + ], + "unicode": "⚡️" + }, + { + "group": 5, + "hexcode": "2744", + "label": "snowflake", + "order": 4043, + "tags": ["cold", "snow", "weather"], + "unicode": "❄️" + }, + { + "group": 5, + "hexcode": "2603", + "label": "snowman", + "order": 4045, + "tags": ["cold", "man", "snow"], + "unicode": "☃️" + }, + { + "group": 5, + "hexcode": "26C4", + "label": "snowman without snow", + "order": 4046, + "tags": ["cold", "man", "snow", "snowman"], + "unicode": "⛄️" + }, + { + "group": 5, + "hexcode": "2604", + "label": "comet", + "order": 4048, + "tags": ["space"], + "unicode": "☄️" + }, + { + "group": 5, + "hexcode": "1F525", + "label": "fire", + "order": 4049, + "tags": ["af", "burn", "flame", "hot", "lit", "litaf", "tool"], + "unicode": "🔥" + }, + { + "group": 5, + "hexcode": "1F4A7", + "label": "droplet", + "order": 4050, + "tags": [ + "cold", + "comic", + "drop", + "nature", + "sad", + "sweat", + "tear", + "water", + "weather" + ], + "unicode": "💧" + }, + { + "group": 5, + "hexcode": "1F30A", + "label": "water wave", + "order": 4051, + "tags": [ + "nature", + "ocean", + "surf", + "surfer", + "surfing", + "water", + "wave" + ], + "unicode": "🌊" + } + ] + }, + { + "name": "Objects", + "emojis": [ + { + "group": 7, + "hexcode": "1F453", + "label": "glasses", + "order": 4148, + "tags": ["clothing", "eye", "eyeglasses", "eyewear"], + "unicode": "👓️" + }, + { + "group": 7, + "hexcode": "1F576", + "label": "sunglasses", + "order": 4150, + "tags": ["dark", "eye", "eyewear", "glasses"], + "unicode": "🕶️" + }, + { + "group": 7, + "hexcode": "1F97D", + "label": "goggles", + "order": 4151, + "tags": ["dive", "eye", "protection", "scuba", "swimming", "welding"], + "unicode": "🥽" + }, + { + "group": 7, + "hexcode": "1F97C", + "label": "lab coat", + "order": 4152, + "tags": [ + "clothes", + "coat", + "doctor", + "dr", + "experiment", + "jacket", + "lab", + "scientist", + "white" + ], + "unicode": "🥼" + }, + { + "group": 7, + "hexcode": "1F9BA", + "label": "safety vest", + "order": 4153, + "tags": ["emergency", "safety", "vest"], + "unicode": "🦺" + }, + { + "group": 7, + "hexcode": "1F454", + "label": "necktie", + "order": 4154, + "tags": ["clothing", "employed", "serious", "shirt", "tie"], + "unicode": "👔" + }, + { + "group": 7, + "hexcode": "1F455", + "label": "t-shirt", + "order": 4155, + "tags": [ + "blue", + "casual", + "clothes", + "clothing", + "collar", + "dressed", + "shirt", + "shopping", + "tshirt", + "weekend" + ], + "unicode": "👕" + }, + { + "group": 7, + "hexcode": "1F456", + "label": "jeans", + "order": 4156, + "tags": [ + "blue", + "casual", + "clothes", + "clothing", + "denim", + "dressed", + "pants", + "shopping", + "trousers", + "weekend" + ], + "unicode": "👖" + }, + { + "group": 7, + "hexcode": "1F9E3", + "label": "scarf", + "order": 4157, + "tags": ["bundle", "cold", "neck", "up"], + "unicode": "🧣" + }, + { + "group": 7, + "hexcode": "1F9E4", + "label": "gloves", + "order": 4158, + "tags": ["hand"], + "unicode": "🧤" + }, + { + "group": 7, + "hexcode": "1F9E5", + "label": "coat", + "order": 4159, + "tags": ["brr", "bundle", "cold", "jacket", "up"], + "unicode": "🧥" + }, + { + "group": 7, + "hexcode": "1F9E6", + "label": "socks", + "order": 4160, + "tags": ["stocking"], + "unicode": "🧦" + }, + { + "group": 7, + "hexcode": "1F457", + "label": "dress", + "order": 4161, + "tags": ["clothes", "clothing", "dressed", "fancy", "shopping"], + "unicode": "👗" + }, + { + "group": 7, + "hexcode": "1F458", + "label": "kimono", + "order": 4162, + "tags": ["clothing", "comfortable"], + "unicode": "👘" + }, + { + "group": 7, + "hexcode": "1F97B", + "label": "sari", + "order": 4163, + "tags": ["clothing", "dress"], + "unicode": "🥻" + }, + { + "group": 7, + "hexcode": "1FA71", + "label": "one-piece swimsuit", + "order": 4164, + "tags": ["bathing", "one-piece", "suit", "swimsuit"], + "unicode": "🩱" + }, + { + "group": 7, + "hexcode": "1FA72", + "label": "briefs", + "order": 4165, + "tags": ["bathing", "one-piece", "suit", "swimsuit", "underwear"], + "unicode": "🩲" + }, + { + "group": 7, + "hexcode": "1FA73", + "label": "shorts", + "order": 4166, + "tags": ["bathing", "pants", "suit", "swimsuit", "underwear"], + "unicode": "🩳" + }, + { + "group": 7, + "hexcode": "1F459", + "label": "bikini", + "order": 4167, + "tags": ["bathing", "beach", "clothing", "pool", "suit", "swim"], + "unicode": "👙" + }, + { + "group": 7, + "hexcode": "1F45A", + "label": "woman’s clothes", + "order": 4168, + "tags": [ + "blouse", + "clothes", + "clothing", + "collar", + "dress", + "dressed", + "lady", + "shirt", + "shopping", + "woman", + "woman’s" + ], + "unicode": "👚" + }, + { + "group": 7, + "hexcode": "1FAAD", + "label": "folding hand fan", + "order": 4169, + "tags": [ + "clack", + "clap", + "cool", + "cooling", + "dance", + "fan", + "flirt", + "flutter", + "folding", + "hand", + "hot", + "shy" + ], + "unicode": "🪭" + }, + { + "group": 7, + "hexcode": "1F45B", + "label": "purse", + "order": 4170, + "tags": [ + "clothes", + "clothing", + "coin", + "dress", + "fancy", + "handbag", + "shopping" + ], + "unicode": "👛" + }, + { + "group": 7, + "hexcode": "1F45C", + "label": "handbag", + "order": 4171, + "tags": [ + "bag", + "clothes", + "clothing", + "dress", + "lady", + "purse", + "shopping" + ], + "unicode": "👜" + }, + { + "group": 7, + "hexcode": "1F45D", + "label": "clutch bag", + "order": 4172, + "tags": [ + "bag", + "clothes", + "clothing", + "clutch", + "dress", + "handbag", + "pouch", + "purse" + ], + "unicode": "👝" + }, + { + "group": 7, + "hexcode": "1F6CD", + "label": "shopping bags", + "order": 4174, + "tags": ["bag", "bags", "hotel", "shopping"], + "unicode": "🛍️" + }, + { + "group": 7, + "hexcode": "1F392", + "label": "backpack", + "order": 4175, + "tags": [ + "backpacking", + "bag", + "bookbag", + "education", + "rucksack", + "satchel", + "school" + ], + "unicode": "🎒" + }, + { + "group": 7, + "hexcode": "1FA74", + "label": "thong sandal", + "order": 4176, + "tags": [ + "beach", + "flip", + "flop", + "sandal", + "sandals", + "shoe", + "thong", + "thongs", + "zōri" + ], + "unicode": "🩴" + }, + { + "group": 7, + "hexcode": "1F45E", + "label": "man’s shoe", + "order": 4177, + "tags": [ + "brown", + "clothes", + "clothing", + "feet", + "foot", + "kick", + "man", + "man’s", + "shoe", + "shoes", + "shopping" + ], + "unicode": "👞" + }, + { + "group": 7, + "hexcode": "1F45F", + "label": "running shoe", + "order": 4178, + "tags": [ + "athletic", + "clothes", + "clothing", + "fast", + "kick", + "running", + "shoe", + "shoes", + "shopping", + "sneaker", + "tennis" + ], + "unicode": "👟" + }, + { + "group": 7, + "hexcode": "1F97E", + "label": "hiking boot", + "order": 4179, + "tags": [ + "backpacking", + "boot", + "brown", + "camping", + "hiking", + "outdoors", + "shoe" + ], + "unicode": "🥾" + }, + { + "group": 7, + "hexcode": "1F97F", + "label": "flat shoe", + "order": 4180, + "tags": [ + "ballet", + "comfy", + "flat", + "flats", + "shoe", + "slip-on", + "slipper" + ], + "unicode": "🥿" + }, + { + "group": 7, + "hexcode": "1F460", + "label": "high-heeled shoe", + "order": 4181, + "tags": [ + "clothes", + "clothing", + "dress", + "fashion", + "heel", + "heels", + "high-heeled", + "shoe", + "shoes", + "shopping", + "stiletto", + "woman" + ], + "unicode": "👠" + }, + { + "group": 7, + "hexcode": "1F461", + "label": "woman’s sandal", + "order": 4182, + "tags": ["clothing", "sandal", "shoe", "woman", "woman’s"], + "unicode": "👡" + }, + { + "group": 7, + "hexcode": "1FA70", + "label": "ballet shoes", + "order": 4183, + "tags": ["ballet", "dance", "shoes"], + "unicode": "🩰" + }, + { + "group": 7, + "hexcode": "1F462", + "label": "woman’s boot", + "order": 4184, + "tags": [ + "boot", + "clothes", + "clothing", + "dress", + "shoe", + "shoes", + "shopping", + "woman", + "woman’s" + ], + "unicode": "👢" + }, + { + "group": 7, + "hexcode": "1FAAE", + "label": "hair pick", + "order": 4185, + "tags": ["afro", "comb", "groom", "hair", "pick"], + "unicode": "🪮" + }, + { + "group": 7, + "hexcode": "1F451", + "label": "crown", + "order": 4186, + "tags": [ + "clothing", + "family", + "king", + "medieval", + "queen", + "royal", + "royalty", + "win" + ], + "unicode": "👑" + }, + { + "group": 7, + "hexcode": "1F452", + "label": "woman’s hat", + "order": 4187, + "tags": [ + "clothes", + "clothing", + "garden", + "hat", + "hats", + "party", + "woman", + "woman’s" + ], + "unicode": "👒" + }, + { + "group": 7, + "hexcode": "1F3A9", + "label": "top hat", + "order": 4188, + "tags": [ + "clothes", + "clothing", + "fancy", + "formal", + "hat", + "magic", + "top", + "tophat" + ], + "unicode": "🎩" + }, + { + "group": 7, + "hexcode": "1F393", + "label": "graduation cap", + "order": 4189, + "tags": [ + "cap", + "celebration", + "clothing", + "education", + "graduation", + "hat", + "scholar" + ], + "unicode": "🎓️" + }, + { + "group": 7, + "hexcode": "1F9E2", + "label": "billed cap", + "order": 4190, + "tags": ["baseball", "bent", "billed", "cap", "dad", "hat"], + "unicode": "🧢" + }, + { + "group": 7, + "hexcode": "1FA96", + "label": "military helmet", + "order": 4191, + "tags": ["army", "helmet", "military", "soldier", "war", "warrior"], + "unicode": "🪖" + }, + { + "group": 7, + "hexcode": "26D1", + "label": "rescue worker’s helmet", + "order": 4193, + "tags": ["aid", "cross", "face", "hat", "helmet", "rescue", "worker’s"], + "unicode": "⛑️" + }, + { + "group": 7, + "hexcode": "1F4FF", + "label": "prayer beads", + "order": 4194, + "tags": ["beads", "clothing", "necklace", "prayer", "religion"], + "unicode": "📿" + }, + { + "group": 7, + "hexcode": "1F484", + "label": "lipstick", + "order": 4195, + "tags": ["cosmetics", "date", "makeup"], + "unicode": "💄" + }, + { + "group": 7, + "hexcode": "1F48D", + "label": "ring", + "order": 4196, + "tags": [ + "diamond", + "engaged", + "engagement", + "married", + "romance", + "shiny", + "sparkling", + "wedding" + ], + "unicode": "💍" + }, + { + "group": 7, + "hexcode": "1F48E", + "label": "gem stone", + "order": 4197, + "tags": [ + "diamond", + "engagement", + "gem", + "jewel", + "money", + "romance", + "stone", + "wedding" + ], + "unicode": "💎" + }, + { + "group": 7, + "hexcode": "1F507", + "label": "muted speaker", + "order": 4198, + "tags": ["mute", "muted", "quiet", "silent", "sound", "speaker"], + "unicode": "🔇" + }, + { + "group": 7, + "hexcode": "1F508", + "label": "speaker low volume", + "order": 4199, + "tags": ["low", "soft", "sound", "speaker", "volume"], + "unicode": "🔈️" + }, + { + "group": 7, + "hexcode": "1F509", + "label": "speaker medium volume", + "order": 4200, + "tags": ["medium", "sound", "speaker", "volume"], + "unicode": "🔉" + }, + { + "group": 7, + "hexcode": "1F50A", + "label": "speaker high volume", + "order": 4201, + "tags": ["high", "loud", "music", "sound", "speaker", "volume"], + "unicode": "🔊" + }, + { + "group": 7, + "hexcode": "1F4E2", + "label": "loudspeaker", + "order": 4202, + "tags": ["address", "communication", "loud", "public", "sound"], + "unicode": "📢" + }, + { + "group": 7, + "hexcode": "1F4E3", + "label": "megaphone", + "order": 4203, + "tags": ["cheering", "sound"], + "unicode": "📣" + }, + { + "group": 7, + "hexcode": "1F4EF", + "label": "postal horn", + "order": 4204, + "tags": ["horn", "post", "postal"], + "unicode": "📯" + }, + { + "group": 7, + "hexcode": "1F514", + "label": "bell", + "order": 4205, + "tags": ["break", "church", "sound"], + "unicode": "🔔" + }, + { + "group": 7, + "hexcode": "1F515", + "label": "bell with slash", + "order": 4206, + "tags": [ + "bell", + "forbidden", + "mute", + "no", + "not", + "prohibited", + "quiet", + "silent", + "slash", + "sound" + ], + "unicode": "🔕" + }, + { + "group": 7, + "hexcode": "1F3BC", + "label": "musical score", + "order": 4207, + "tags": ["music", "musical", "note", "score"], + "unicode": "🎼" + }, + { + "group": 7, + "hexcode": "1F3B5", + "label": "musical note", + "order": 4208, + "tags": ["music", "musical", "note", "sound"], + "unicode": "🎵" + }, + { + "group": 7, + "hexcode": "1F3B6", + "label": "musical notes", + "order": 4209, + "tags": ["music", "musical", "note", "notes", "sound"], + "unicode": "🎶" + }, + { + "group": 7, + "hexcode": "1F399", + "label": "studio microphone", + "order": 4211, + "tags": ["mic", "microphone", "music", "studio"], + "unicode": "🎙️" + }, + { + "group": 7, + "hexcode": "1F39A", + "label": "level slider", + "order": 4213, + "tags": ["level", "music", "slider"], + "unicode": "🎚️" + }, + { + "group": 7, + "hexcode": "1F39B", + "label": "control knobs", + "order": 4215, + "tags": ["control", "knobs", "music"], + "unicode": "🎛️" + }, + { + "group": 7, + "hexcode": "1F3A4", + "label": "microphone", + "order": 4216, + "tags": ["karaoke", "mic", "music", "sing", "sound"], + "unicode": "🎤" + }, + { + "group": 7, + "hexcode": "1F3A7", + "label": "headphone", + "order": 4217, + "tags": ["earbud", "sound"], + "unicode": "🎧️" + }, + { + "group": 7, + "hexcode": "1F4FB", + "label": "radio", + "order": 4218, + "tags": ["entertainment", "tbt", "video"], + "unicode": "📻️" + }, + { + "group": 7, + "hexcode": "1F3B7", + "label": "saxophone", + "order": 4219, + "tags": ["instrument", "music", "sax"], + "unicode": "🎷" + }, + { + "group": 7, + "hexcode": "1FA97", + "label": "accordion", + "order": 4220, + "tags": [ + "box", + "concertina", + "instrument", + "music", + "squeeze", + "squeezebox" + ], + "unicode": "🪗" + }, + { + "group": 7, + "hexcode": "1F3B8", + "label": "guitar", + "order": 4221, + "tags": ["instrument", "music", "strat"], + "unicode": "🎸" + }, + { + "group": 7, + "hexcode": "1F3B9", + "label": "musical keyboard", + "order": 4222, + "tags": ["instrument", "keyboard", "music", "musical", "piano"], + "unicode": "🎹" + }, + { + "group": 7, + "hexcode": "1F3BA", + "label": "trumpet", + "order": 4223, + "tags": ["instrument", "music"], + "unicode": "🎺" + }, + { + "group": 7, + "hexcode": "1F3BB", + "label": "violin", + "order": 4224, + "tags": ["instrument", "music"], + "unicode": "🎻" + }, + { + "group": 7, + "hexcode": "1FA95", + "label": "banjo", + "order": 4225, + "tags": ["music", "stringed"], + "unicode": "🪕" + }, + { + "group": 7, + "hexcode": "1F941", + "label": "drum", + "order": 4226, + "tags": ["drumsticks", "music"], + "unicode": "🥁" + }, + { + "group": 7, + "hexcode": "1FA98", + "label": "long drum", + "order": 4227, + "tags": ["beat", "conga", "drum", "instrument", "long", "rhythm"], + "unicode": "🪘" + }, + { + "group": 7, + "hexcode": "1FA87", + "label": "maracas", + "order": 4228, + "tags": [ + "cha", + "dance", + "instrument", + "music", + "party", + "percussion", + "rattle", + "shake", + "shaker" + ], + "unicode": "🪇" + }, + { + "group": 7, + "hexcode": "1FA88", + "label": "flute", + "order": 4229, + "tags": [ + "band", + "fife", + "flautist", + "instrument", + "marching", + "music", + "orchestra", + "piccolo", + "pipe", + "recorder", + "woodwind" + ], + "unicode": "🪈" + }, + { + "group": 7, + "hexcode": "1FA89", + "label": "harp", + "order": 4230, + "tags": ["cupid", "instrument", "love", "music", "orchestra"], + "unicode": "🪉" + }, + { + "group": 7, + "hexcode": "1F4F1", + "label": "mobile phone", + "order": 4231, + "tags": ["cell", "communication", "mobile", "phone", "telephone"], + "unicode": "📱" + }, + { + "group": 7, + "hexcode": "1F4F2", + "label": "mobile phone with arrow", + "order": 4232, + "tags": [ + "arrow", + "build", + "call", + "cell", + "communication", + "mobile", + "phone", + "receive", + "telephone" + ], + "unicode": "📲" + }, + { + "group": 7, + "hexcode": "260E", + "label": "telephone", + "order": 4234, + "tags": ["phone"], + "unicode": "☎️" + }, + { + "group": 7, + "hexcode": "1F4DE", + "label": "telephone receiver", + "order": 4235, + "tags": ["communication", "phone", "receiver", "telephone", "voip"], + "unicode": "📞" + }, + { + "group": 7, + "hexcode": "1F4DF", + "label": "pager", + "order": 4236, + "tags": ["communication"], + "unicode": "📟️" + }, + { + "group": 7, + "hexcode": "1F4E0", + "label": "fax machine", + "order": 4237, + "tags": ["communication", "fax", "machine"], + "unicode": "📠" + }, + { + "group": 7, + "hexcode": "1F50B", + "label": "battery", + "order": 4238, + "tags": ["battery"], + "unicode": "🔋" + }, + { + "group": 7, + "hexcode": "1FAAB", + "label": "low battery", + "order": 4239, + "tags": ["battery", "drained", "electronic", "energy", "low", "power"], + "unicode": "🪫" + }, + { + "group": 7, + "hexcode": "1F50C", + "label": "electric plug", + "order": 4240, + "tags": ["electric", "electricity", "plug"], + "unicode": "🔌" + }, + { + "group": 7, + "hexcode": "1F4BB", + "label": "laptop", + "order": 4241, + "tags": ["computer", "office", "pc", "personal"], + "unicode": "💻️" + }, + { + "group": 7, + "hexcode": "1F5A5", + "label": "desktop computer", + "order": 4243, + "tags": ["computer", "desktop", "monitor"], + "unicode": "🖥️" + }, + { + "group": 7, + "hexcode": "1F5A8", + "label": "printer", + "order": 4245, + "tags": ["computer"], + "unicode": "🖨️" + }, + { + "group": 7, + "hexcode": "2328", + "label": "keyboard", + "order": 4247, + "tags": ["computer"], + "unicode": "⌨️" + }, + { + "group": 7, + "hexcode": "1F5B1", + "label": "computer mouse", + "order": 4249, + "tags": ["computer", "mouse"], + "unicode": "🖱️" + }, + { + "group": 7, + "hexcode": "1F5B2", + "label": "trackball", + "order": 4251, + "tags": ["computer"], + "unicode": "🖲️" + }, + { + "group": 7, + "hexcode": "1F4BD", + "label": "computer disk", + "order": 4252, + "tags": ["computer", "disk", "minidisk", "optical"], + "unicode": "💽" + }, + { + "group": 7, + "hexcode": "1F4BE", + "label": "floppy disk", + "order": 4253, + "tags": ["computer", "disk", "floppy"], + "unicode": "💾" + }, + { + "group": 7, + "hexcode": "1F4BF", + "label": "optical disk", + "order": 4254, + "tags": ["blu-ray", "cd", "computer", "disk", "dvd", "optical"], + "unicode": "💿️" + }, + { + "group": 7, + "hexcode": "1F4C0", + "label": "dvd", + "order": 4255, + "tags": ["blu-ray", "cd", "computer", "disk", "optical"], + "unicode": "📀" + }, + { + "group": 7, + "hexcode": "1F9EE", + "label": "abacus", + "order": 4256, + "tags": ["calculation", "calculator"], + "unicode": "🧮" + }, + { + "group": 7, + "hexcode": "1F3A5", + "label": "movie camera", + "order": 4257, + "tags": [ + "bollywood", + "camera", + "cinema", + "film", + "hollywood", + "movie", + "record" + ], + "unicode": "🎥" + }, + { + "group": 7, + "hexcode": "1F39E", + "label": "film frames", + "order": 4259, + "tags": ["cinema", "film", "frames", "movie"], + "unicode": "🎞️" + }, + { + "group": 7, + "hexcode": "1F4FD", + "label": "film projector", + "order": 4261, + "tags": ["cinema", "film", "movie", "projector", "video"], + "unicode": "📽️" + }, + { + "group": 7, + "hexcode": "1F3AC", + "label": "clapper board", + "order": 4262, + "tags": ["action", "board", "clapper", "movie"], + "unicode": "🎬️" + }, + { + "group": 7, + "hexcode": "1F4FA", + "label": "television", + "order": 4263, + "tags": ["tv", "video"], + "unicode": "📺️" + }, + { + "group": 7, + "hexcode": "1F4F7", + "label": "camera", + "order": 4264, + "tags": ["photo", "selfie", "snap", "tbt", "trip", "video"], + "unicode": "📷️" + }, + { + "group": 7, + "hexcode": "1F4F8", + "label": "camera with flash", + "order": 4265, + "tags": ["camera", "flash", "video"], + "unicode": "📸" + }, + { + "group": 7, + "hexcode": "1F4F9", + "label": "video camera", + "order": 4266, + "tags": ["camcorder", "camera", "tbt", "video"], + "unicode": "📹️" + }, + { + "group": 7, + "hexcode": "1F4FC", + "label": "videocassette", + "order": 4267, + "tags": ["old", "school", "tape", "vcr", "vhs", "video"], + "unicode": "📼" + }, + { + "group": 7, + "hexcode": "1F50D", + "label": "magnifying glass tilted left", + "order": 4268, + "tags": [ + "glass", + "lab", + "left", + "left-pointing", + "magnifying", + "science", + "search", + "tilted", + "tool" + ], + "unicode": "🔍️" + }, + { + "group": 7, + "hexcode": "1F50E", + "label": "magnifying glass tilted right", + "order": 4269, + "tags": [ + "contact", + "glass", + "lab", + "magnifying", + "right", + "right-pointing", + "science", + "search", + "tilted", + "tool" + ], + "unicode": "🔎" + }, + { + "group": 7, + "hexcode": "1F56F", + "label": "candle", + "order": 4271, + "tags": ["light"], + "unicode": "🕯️" + }, + { + "group": 7, + "hexcode": "1F4A1", + "label": "light bulb", + "order": 4272, + "tags": ["bulb", "comic", "electric", "idea", "light"], + "unicode": "💡" + }, + { + "group": 7, + "hexcode": "1F526", + "label": "flashlight", + "order": 4273, + "tags": ["electric", "light", "tool", "torch"], + "unicode": "🔦" + }, + { + "group": 7, + "hexcode": "1F3EE", + "label": "red paper lantern", + "order": 4274, + "tags": ["bar", "lantern", "light", "paper", "red", "restaurant"], + "unicode": "🏮" + }, + { + "group": 7, + "hexcode": "1FA94", + "label": "diya lamp", + "order": 4275, + "tags": ["diya", "lamp", "light", "oil"], + "unicode": "🪔" + }, + { + "group": 7, + "hexcode": "1F4D4", + "label": "notebook with decorative cover", + "order": 4276, + "tags": [ + "book", + "cover", + "decorated", + "decorative", + "education", + "notebook", + "school", + "writing" + ], + "unicode": "📔" + }, + { + "group": 7, + "hexcode": "1F4D5", + "label": "closed book", + "order": 4277, + "tags": ["book", "closed", "education"], + "unicode": "📕" + }, + { + "group": 7, + "hexcode": "1F4D6", + "label": "open book", + "order": 4278, + "tags": [ + "book", + "education", + "fantasy", + "knowledge", + "library", + "novels", + "open", + "reading" + ], + "unicode": "📖" + }, + { + "group": 7, + "hexcode": "1F4D7", + "label": "green book", + "order": 4279, + "tags": ["book", "education", "fantasy", "green", "library", "reading"], + "unicode": "📗" + }, + { + "group": 7, + "hexcode": "1F4D8", + "label": "blue book", + "order": 4280, + "tags": ["blue", "book", "education", "fantasy", "library", "reading"], + "unicode": "📘" + }, + { + "group": 7, + "hexcode": "1F4D9", + "label": "orange book", + "order": 4281, + "tags": [ + "book", + "education", + "fantasy", + "library", + "orange", + "reading" + ], + "unicode": "📙" + }, + { + "group": 7, + "hexcode": "1F4DA", + "label": "books", + "order": 4282, + "tags": [ + "book", + "education", + "fantasy", + "knowledge", + "library", + "novels", + "reading", + "school", + "study" + ], + "unicode": "📚️" + }, + { + "group": 7, + "hexcode": "1F4D3", + "label": "notebook", + "order": 4283, + "tags": ["notebook"], + "unicode": "📓" + }, + { + "group": 7, + "hexcode": "1F4D2", + "label": "ledger", + "order": 4284, + "tags": ["notebook"], + "unicode": "📒" + }, + { + "group": 7, + "hexcode": "1F4C3", + "label": "page with curl", + "order": 4285, + "tags": ["curl", "document", "page", "paper"], + "unicode": "📃" + }, + { + "group": 7, + "hexcode": "1F4DC", + "label": "scroll", + "order": 4286, + "tags": ["paper"], + "unicode": "📜" + }, + { + "group": 7, + "hexcode": "1F4C4", + "label": "page facing up", + "order": 4287, + "tags": ["document", "facing", "page", "paper", "up"], + "unicode": "📄" + }, + { + "group": 7, + "hexcode": "1F4F0", + "label": "newspaper", + "order": 4288, + "tags": ["communication", "news", "paper"], + "unicode": "📰" + }, + { + "group": 7, + "hexcode": "1F5DE", + "label": "rolled-up newspaper", + "order": 4290, + "tags": ["news", "newspaper", "paper", "rolled", "rolled-up"], + "unicode": "🗞️" + }, + { + "group": 7, + "hexcode": "1F4D1", + "label": "bookmark tabs", + "order": 4291, + "tags": ["bookmark", "mark", "marker", "tabs"], + "unicode": "📑" + }, + { + "group": 7, + "hexcode": "1F516", + "label": "bookmark", + "order": 4292, + "tags": ["mark"], + "unicode": "🔖" + }, + { + "group": 7, + "hexcode": "1F3F7", + "label": "label", + "order": 4294, + "tags": ["tag"], + "unicode": "🏷️" + }, + { + "group": 7, + "hexcode": "1F4B0", + "label": "money bag", + "order": 4295, + "tags": [ + "bag", + "bank", + "bet", + "billion", + "cash", + "cost", + "dollar", + "gold", + "million", + "money", + "moneybag", + "paid", + "paying", + "pot", + "rich", + "win" + ], + "unicode": "💰️" + }, + { + "group": 7, + "hexcode": "1FA99", + "label": "coin", + "order": 4296, + "tags": [ + "dollar", + "euro", + "gold", + "metal", + "money", + "rich", + "silver", + "treasure" + ], + "unicode": "🪙" + }, + { + "group": 7, + "hexcode": "1F4B4", + "label": "yen banknote", + "order": 4297, + "tags": [ + "bank", + "banknote", + "bill", + "currency", + "money", + "note", + "yen" + ], + "unicode": "💴" + }, + { + "group": 7, + "hexcode": "1F4B5", + "label": "dollar banknote", + "order": 4298, + "tags": [ + "bank", + "banknote", + "bill", + "currency", + "dollar", + "money", + "note" + ], + "unicode": "💵" + }, + { + "group": 7, + "hexcode": "1F4B6", + "label": "euro banknote", + "order": 4299, + "tags": [ + "100", + "bank", + "banknote", + "bill", + "currency", + "euro", + "money", + "note", + "rich" + ], + "unicode": "💶" + }, + { + "group": 7, + "hexcode": "1F4B7", + "label": "pound banknote", + "order": 4300, + "tags": [ + "bank", + "banknote", + "bill", + "billion", + "cash", + "currency", + "money", + "note", + "pound", + "pounds" + ], + "unicode": "💷" + }, + { + "group": 7, + "hexcode": "1F4B8", + "label": "money with wings", + "order": 4301, + "tags": [ + "bank", + "banknote", + "bill", + "billion", + "cash", + "dollar", + "fly", + "million", + "money", + "note", + "pay", + "wings" + ], + "unicode": "💸" + }, + { + "group": 7, + "hexcode": "1F4B3", + "label": "credit card", + "order": 4302, + "tags": ["bank", "card", "cash", "charge", "credit", "money", "pay"], + "unicode": "💳️" + }, + { + "group": 7, + "hexcode": "1F9FE", + "label": "receipt", + "order": 4303, + "tags": ["accounting", "bookkeeping", "evidence", "invoice", "proof"], + "unicode": "🧾" + }, + { + "group": 7, + "hexcode": "1F4B9", + "label": "chart increasing with yen", + "order": 4304, + "tags": [ + "bank", + "chart", + "currency", + "graph", + "growth", + "increasing", + "market", + "money", + "rise", + "trend", + "upward", + "yen" + ], + "unicode": "💹" + }, + { + "group": 7, + "hexcode": "2709", + "label": "envelope", + "order": 4306, + "tags": ["e-mail", "email", "letter"], + "unicode": "✉️" + }, + { + "group": 7, + "hexcode": "1F4E7", + "label": "e-mail", + "order": 4307, + "tags": ["email", "letter", "mail"], + "unicode": "📧" + }, + { + "group": 7, + "hexcode": "1F4E8", + "label": "incoming envelope", + "order": 4308, + "tags": [ + "delivering", + "e-mail", + "email", + "envelope", + "incoming", + "letter", + "mail", + "receive", + "sent" + ], + "unicode": "📨" + }, + { + "group": 7, + "hexcode": "1F4E9", + "label": "envelope with arrow", + "order": 4309, + "tags": [ + "arrow", + "communication", + "down", + "e-mail", + "email", + "envelope", + "letter", + "mail", + "outgoing", + "send", + "sent" + ], + "unicode": "📩" + }, + { + "group": 7, + "hexcode": "1F4E4", + "label": "outbox tray", + "order": 4310, + "tags": ["box", "email", "letter", "mail", "outbox", "sent", "tray"], + "unicode": "📤️" + }, + { + "group": 7, + "hexcode": "1F4E5", + "label": "inbox tray", + "order": 4311, + "tags": [ + "box", + "email", + "inbox", + "letter", + "mail", + "receive", + "tray", + "zero" + ], + "unicode": "📥️" + }, + { + "group": 7, + "hexcode": "1F4E6", + "label": "package", + "order": 4312, + "tags": ["box", "communication", "delivery", "parcel", "shipping"], + "unicode": "📦️" + }, + { + "group": 7, + "hexcode": "1F4EB", + "label": "closed mailbox with raised flag", + "order": 4313, + "tags": [ + "closed", + "communication", + "flag", + "mail", + "mailbox", + "postbox", + "raised" + ], + "unicode": "📫️" + }, + { + "group": 7, + "hexcode": "1F4EA", + "label": "closed mailbox with lowered flag", + "order": 4314, + "tags": ["closed", "flag", "lowered", "mail", "mailbox", "postbox"], + "unicode": "📪️" + }, + { + "group": 7, + "hexcode": "1F4EC", + "label": "open mailbox with raised flag", + "order": 4315, + "tags": ["flag", "mail", "mailbox", "open", "postbox", "raised"], + "unicode": "📬️" + }, + { + "group": 7, + "hexcode": "1F4ED", + "label": "open mailbox with lowered flag", + "order": 4316, + "tags": ["flag", "lowered", "mail", "mailbox", "open", "postbox"], + "unicode": "📭️" + }, + { + "group": 7, + "hexcode": "1F4EE", + "label": "postbox", + "order": 4317, + "tags": ["mail", "mailbox"], + "unicode": "📮" + }, + { + "group": 7, + "hexcode": "1F5F3", + "label": "ballot box with ballot", + "order": 4319, + "tags": ["ballot", "box"], + "unicode": "🗳️" + }, + { + "group": 7, + "hexcode": "270F", + "label": "pencil", + "order": 4321, + "tags": ["pencil"], + "unicode": "✏️" + }, + { + "group": 7, + "hexcode": "2712", + "label": "black nib", + "order": 4323, + "tags": ["black", "nib", "pen"], + "unicode": "✒️" + }, + { + "group": 7, + "hexcode": "1F58B", + "label": "fountain pen", + "order": 4325, + "tags": ["fountain", "pen"], + "unicode": "🖋️" + }, + { + "group": 7, + "hexcode": "1F58A", + "label": "pen", + "order": 4327, + "tags": ["ballpoint"], + "unicode": "🖊️" + }, + { + "group": 7, + "hexcode": "1F58C", + "label": "paintbrush", + "order": 4329, + "tags": ["painting"], + "unicode": "🖌️" + }, + { + "group": 7, + "hexcode": "1F58D", + "label": "crayon", + "order": 4331, + "tags": ["crayon"], + "unicode": "🖍️" + }, + { + "group": 7, + "hexcode": "1F4DD", + "label": "memo", + "order": 4332, + "tags": ["communication", "media", "notes", "pencil"], + "unicode": "📝" + }, + { + "group": 7, + "hexcode": "1F4BC", + "label": "briefcase", + "order": 4333, + "tags": ["office"], + "unicode": "💼" + }, + { + "group": 7, + "hexcode": "1F4C1", + "label": "file folder", + "order": 4334, + "tags": ["file", "folder"], + "unicode": "📁" + }, + { + "group": 7, + "hexcode": "1F4C2", + "label": "open file folder", + "order": 4335, + "tags": ["file", "folder", "open"], + "unicode": "📂" + }, + { + "group": 7, + "hexcode": "1F5C2", + "label": "card index dividers", + "order": 4337, + "tags": ["card", "dividers", "index"], + "unicode": "🗂️" + }, + { + "group": 7, + "hexcode": "1F4C5", + "label": "calendar", + "order": 4338, + "tags": ["date"], + "unicode": "📅" + }, + { + "group": 7, + "hexcode": "1F4C6", + "label": "tear-off calendar", + "order": 4339, + "tags": ["calendar", "tear-off"], + "unicode": "📆" + }, + { + "group": 7, + "hexcode": "1F5D2", + "label": "spiral notepad", + "order": 4341, + "tags": ["note", "notepad", "pad", "spiral"], + "unicode": "🗒️" + }, + { + "group": 7, + "hexcode": "1F5D3", + "label": "spiral calendar", + "order": 4343, + "tags": ["calendar", "pad", "spiral"], + "unicode": "🗓️" + }, + { + "group": 7, + "hexcode": "1F4C7", + "label": "card index", + "order": 4344, + "tags": ["card", "index", "old", "rolodex", "school"], + "unicode": "📇" + }, + { + "group": 7, + "hexcode": "1F4C8", + "label": "chart increasing", + "order": 4345, + "tags": [ + "chart", + "data", + "graph", + "growth", + "increasing", + "right", + "trend", + "up", + "upward" + ], + "unicode": "📈" + }, + { + "group": 7, + "hexcode": "1F4C9", + "label": "chart decreasing", + "order": 4346, + "tags": [ + "chart", + "data", + "decreasing", + "down", + "downward", + "graph", + "negative", + "trend" + ], + "unicode": "📉" + }, + { + "group": 7, + "hexcode": "1F4CA", + "label": "bar chart", + "order": 4347, + "tags": ["bar", "chart", "data", "graph"], + "unicode": "📊" + }, + { + "group": 7, + "hexcode": "1F4CB", + "label": "clipboard", + "order": 4348, + "tags": ["do", "list", "notes"], + "unicode": "📋️" + }, + { + "group": 7, + "hexcode": "1F4CC", + "label": "pushpin", + "order": 4349, + "tags": ["collage", "pin"], + "unicode": "📌" + }, + { + "group": 7, + "hexcode": "1F4CD", + "label": "round pushpin", + "order": 4350, + "tags": ["location", "map", "pin", "pushpin", "round"], + "unicode": "📍" + }, + { + "group": 7, + "hexcode": "1F4CE", + "label": "paperclip", + "order": 4351, + "tags": ["paperclip"], + "unicode": "📎" + }, + { + "group": 7, + "hexcode": "1F587", + "label": "linked paperclips", + "order": 4353, + "tags": ["link", "linked", "paperclip", "paperclips"], + "unicode": "🖇️" + }, + { + "group": 7, + "hexcode": "1F4CF", + "label": "straight ruler", + "order": 4354, + "tags": ["angle", "edge", "math", "ruler", "straight", "straightedge"], + "unicode": "📏" + }, + { + "group": 7, + "hexcode": "1F4D0", + "label": "triangular ruler", + "order": 4355, + "tags": [ + "angle", + "math", + "rule", + "ruler", + "set", + "slide", + "triangle", + "triangular" + ], + "unicode": "📐" + }, + { + "group": 7, + "hexcode": "2702", + "label": "scissors", + "order": 4357, + "tags": ["cut", "cutting", "paper", "tool"], + "unicode": "✂️" + }, + { + "group": 7, + "hexcode": "1F5C3", + "label": "card file box", + "order": 4359, + "tags": ["box", "card", "file"], + "unicode": "🗃️" + }, + { + "group": 7, + "hexcode": "1F5C4", + "label": "file cabinet", + "order": 4361, + "tags": ["cabinet", "file", "filing", "paper"], + "unicode": "🗄️" + }, + { + "group": 7, + "hexcode": "1F5D1", + "label": "wastebasket", + "order": 4363, + "tags": ["can", "garbage", "trash", "waste"], + "unicode": "🗑️" + }, + { + "group": 7, + "hexcode": "1F512", + "label": "locked", + "order": 4364, + "tags": ["closed", "lock", "private"], + "unicode": "🔒️" + }, + { + "group": 7, + "hexcode": "1F513", + "label": "unlocked", + "order": 4365, + "tags": ["cracked", "lock", "open", "unlock"], + "unicode": "🔓️" + }, + { + "group": 7, + "hexcode": "1F50F", + "label": "locked with pen", + "order": 4366, + "tags": ["ink", "lock", "locked", "nib", "pen", "privacy"], + "unicode": "🔏" + }, + { + "group": 7, + "hexcode": "1F510", + "label": "locked with key", + "order": 4367, + "tags": ["bike", "closed", "key", "lock", "locked", "secure"], + "unicode": "🔐" + }, + { + "group": 7, + "hexcode": "1F511", + "label": "key", + "order": 4368, + "tags": ["keys", "lock", "major", "password", "unlock"], + "unicode": "🔑" + }, + { + "group": 7, + "hexcode": "1F5DD", + "label": "old key", + "order": 4370, + "tags": ["clue", "key", "lock", "old"], + "unicode": "🗝️" + }, + { + "group": 7, + "hexcode": "1F528", + "label": "hammer", + "order": 4371, + "tags": ["home", "improvement", "repairs", "tool"], + "unicode": "🔨" + }, + { + "group": 7, + "hexcode": "1FA93", + "label": "axe", + "order": 4372, + "tags": ["ax", "chop", "hatchet", "split", "wood"], + "unicode": "🪓" + }, + { + "group": 7, + "hexcode": "26CF", + "label": "pick", + "order": 4374, + "tags": ["hammer", "mining", "tool"], + "unicode": "⛏️" + }, + { + "group": 7, + "hexcode": "2692", + "label": "hammer and pick", + "order": 4376, + "tags": ["hammer", "pick", "tool"], + "unicode": "⚒️" + }, + { + "group": 7, + "hexcode": "1F6E0", + "label": "hammer and wrench", + "order": 4378, + "tags": ["hammer", "spanner", "tool", "wrench"], + "unicode": "🛠️" + }, + { + "group": 7, + "hexcode": "1F5E1", + "label": "dagger", + "order": 4380, + "tags": ["knife", "weapon"], + "unicode": "🗡️" + }, + { + "group": 7, + "hexcode": "2694", + "label": "crossed swords", + "order": 4382, + "tags": ["crossed", "swords", "weapon"], + "unicode": "⚔️" + }, + { + "group": 7, + "hexcode": "1F4A3", + "label": "bomb", + "order": 4383, + "tags": ["boom", "comic", "dangerous", "explosion", "hot"], + "unicode": "💣️" + }, + { + "group": 7, + "hexcode": "1FA83", + "label": "boomerang", + "order": 4384, + "tags": ["rebound", "repercussion", "weapon"], + "unicode": "🪃" + }, + { + "group": 7, + "hexcode": "1F3F9", + "label": "bow and arrow", + "order": 4385, + "tags": [ + "archer", + "archery", + "arrow", + "bow", + "sagittarius", + "tool", + "weapon", + "zodiac" + ], + "unicode": "🏹" + }, + { + "group": 7, + "hexcode": "1F6E1", + "label": "shield", + "order": 4387, + "tags": ["weapon"], + "unicode": "🛡️" + }, + { + "group": 7, + "hexcode": "1FA9A", + "label": "carpentry saw", + "order": 4388, + "tags": [ + "carpenter", + "carpentry", + "cut", + "lumber", + "saw", + "tool", + "trim" + ], + "unicode": "🪚" + }, + { + "group": 7, + "hexcode": "1F527", + "label": "wrench", + "order": 4389, + "tags": ["home", "improvement", "spanner", "tool"], + "unicode": "🔧" + }, + { + "group": 7, + "hexcode": "1FA9B", + "label": "screwdriver", + "order": 4390, + "tags": ["flathead", "handy", "screw", "tool"], + "unicode": "🪛" + }, + { + "group": 7, + "hexcode": "1F529", + "label": "nut and bolt", + "order": 4391, + "tags": ["bolt", "home", "improvement", "nut", "tool"], + "unicode": "🔩" + }, + { + "group": 7, + "hexcode": "2699", + "label": "gear", + "order": 4393, + "tags": ["cog", "cogwheel", "tool"], + "unicode": "⚙️" + }, + { + "group": 7, + "hexcode": "1F5DC", + "label": "clamp", + "order": 4395, + "tags": ["compress", "tool", "vice"], + "unicode": "🗜️" + }, + { + "group": 7, + "hexcode": "2696", + "label": "balance scale", + "order": 4397, + "tags": [ + "balance", + "justice", + "libra", + "scale", + "scales", + "tool", + "weight", + "zodiac" + ], + "unicode": "⚖️" + }, + { + "group": 7, + "hexcode": "1F9AF", + "label": "white cane", + "order": 4398, + "tags": ["accessibility", "blind", "cane", "probing", "white"], + "unicode": "🦯" + }, + { + "group": 7, + "hexcode": "1F517", + "label": "link", + "order": 4399, + "tags": ["links"], + "unicode": "🔗" + }, + { + "group": 7, + "hexcode": "26D3-FE0F-200D-1F4A5", + "label": "broken chain", + "order": 4400, + "tags": ["break", "breaking", "broken", "chain", "cuffs", "freedom"], + "unicode": "⛓️‍💥" + }, + { + "group": 7, + "hexcode": "26D3", + "label": "chains", + "order": 4403, + "tags": ["chain"], + "unicode": "⛓️" + }, + { + "group": 7, + "hexcode": "1FA9D", + "label": "hook", + "order": 4404, + "tags": ["catch", "crook", "curve", "ensnare", "point", "selling"], + "unicode": "🪝" + }, + { + "group": 7, + "hexcode": "1F9F0", + "label": "toolbox", + "order": 4405, + "tags": ["box", "chest", "mechanic", "red", "tool"], + "unicode": "🧰" + }, + { + "group": 7, + "hexcode": "1F9F2", + "label": "magnet", + "order": 4406, + "tags": [ + "attraction", + "horseshoe", + "magnetic", + "negative", + "positive", + "shape", + "u" + ], + "unicode": "🧲" + }, + { + "group": 7, + "hexcode": "1FA9C", + "label": "ladder", + "order": 4407, + "tags": ["climb", "rung", "step"], + "unicode": "🪜" + }, + { + "group": 7, + "hexcode": "1FA8F", + "label": "shovel", + "order": 4408, + "tags": [ + "bury", + "dig", + "garden", + "hole", + "plant", + "scoop", + "snow", + "spade" + ], + "unicode": "🪏" + }, + { + "group": 7, + "hexcode": "2697", + "label": "alembic", + "order": 4410, + "tags": ["chemistry", "tool"], + "unicode": "⚗️" + }, + { + "group": 7, + "hexcode": "1F9EA", + "label": "test tube", + "order": 4411, + "tags": [ + "chemist", + "chemistry", + "experiment", + "lab", + "science", + "test", + "tube" + ], + "unicode": "🧪" + }, + { + "group": 7, + "hexcode": "1F9EB", + "label": "petri dish", + "order": 4412, + "tags": [ + "bacteria", + "biologist", + "biology", + "culture", + "dish", + "lab", + "petri" + ], + "unicode": "🧫" + }, + { + "group": 7, + "hexcode": "1F9EC", + "label": "dna", + "order": 4413, + "tags": ["biologist", "evolution", "gene", "genetics", "life"], + "unicode": "🧬" + }, + { + "group": 7, + "hexcode": "1F52C", + "label": "microscope", + "order": 4414, + "tags": ["experiment", "lab", "science", "tool"], + "unicode": "🔬" + }, + { + "group": 7, + "hexcode": "1F52D", + "label": "telescope", + "order": 4415, + "tags": ["contact", "extraterrestrial", "science", "tool"], + "unicode": "🔭" + }, + { + "group": 7, + "hexcode": "1F4E1", + "label": "satellite antenna", + "order": 4416, + "tags": [ + "aliens", + "antenna", + "contact", + "dish", + "satellite", + "science" + ], + "unicode": "📡" + }, + { + "group": 7, + "hexcode": "1F489", + "label": "syringe", + "order": 4417, + "tags": [ + "doctor", + "flu", + "medicine", + "needle", + "shot", + "sick", + "tool", + "vaccination" + ], + "unicode": "💉" + }, + { + "group": 7, + "hexcode": "1FA78", + "label": "drop of blood", + "order": 4418, + "tags": [ + "bleed", + "blood", + "donation", + "drop", + "injury", + "medicine", + "menstruation" + ], + "unicode": "🩸" + }, + { + "group": 7, + "hexcode": "1F48A", + "label": "pill", + "order": 4419, + "tags": [ + "doctor", + "drugs", + "medicated", + "medicine", + "pills", + "sick", + "vitamin" + ], + "unicode": "💊" + }, + { + "group": 7, + "hexcode": "1FA79", + "label": "adhesive bandage", + "order": 4420, + "tags": ["adhesive", "bandage"], + "unicode": "🩹" + }, + { + "group": 7, + "hexcode": "1FA7C", + "label": "crutch", + "order": 4421, + "tags": [ + "aid", + "cane", + "disability", + "help", + "hurt", + "injured", + "mobility", + "stick" + ], + "unicode": "🩼" + }, + { + "group": 7, + "hexcode": "1FA7A", + "label": "stethoscope", + "order": 4422, + "tags": ["doctor", "heart", "medicine"], + "unicode": "🩺" + }, + { + "group": 7, + "hexcode": "1FA7B", + "label": "x-ray", + "order": 4423, + "tags": ["bones", "doctor", "medical", "skeleton", "skull", "xray"], + "unicode": "🩻" + }, + { + "group": 7, + "hexcode": "1F6AA", + "label": "door", + "order": 4424, + "tags": ["back", "closet", "front"], + "unicode": "🚪" + }, + { + "group": 7, + "hexcode": "1F6D7", + "label": "elevator", + "order": 4425, + "tags": ["accessibility", "hoist", "lift"], + "unicode": "🛗" + }, + { + "group": 7, + "hexcode": "1FA9E", + "label": "mirror", + "order": 4426, + "tags": ["makeup", "reflection", "reflector", "speculum"], + "unicode": "🪞" + }, + { + "group": 7, + "hexcode": "1FA9F", + "label": "window", + "order": 4427, + "tags": ["air", "frame", "fresh", "opening", "transparent", "view"], + "unicode": "🪟" + }, + { + "group": 7, + "hexcode": "1F6CF", + "label": "bed", + "order": 4429, + "tags": ["hotel", "sleep"], + "unicode": "🛏️" + }, + { + "group": 7, + "hexcode": "1F6CB", + "label": "couch and lamp", + "order": 4431, + "tags": ["couch", "hotel", "lamp"], + "unicode": "🛋️" + }, + { + "group": 7, + "hexcode": "1FA91", + "label": "chair", + "order": 4432, + "tags": ["seat", "sit"], + "unicode": "🪑" + }, + { + "group": 7, + "hexcode": "1F6BD", + "label": "toilet", + "order": 4433, + "tags": ["bathroom"], + "unicode": "🚽" + }, + { + "group": 7, + "hexcode": "1FAA0", + "label": "plunger", + "order": 4434, + "tags": ["cup", "force", "plumber", "poop", "suction", "toilet"], + "unicode": "🪠" + }, + { + "group": 7, + "hexcode": "1F6BF", + "label": "shower", + "order": 4435, + "tags": ["water"], + "unicode": "🚿" + }, + { + "group": 7, + "hexcode": "1F6C1", + "label": "bathtub", + "order": 4436, + "tags": ["bath"], + "unicode": "🛁" + }, + { + "group": 7, + "hexcode": "1FAA4", + "label": "mouse trap", + "order": 4437, + "tags": [ + "bait", + "cheese", + "lure", + "mouse", + "mousetrap", + "snare", + "trap" + ], + "unicode": "🪤" + }, + { + "group": 7, + "hexcode": "1FA92", + "label": "razor", + "order": 4438, + "tags": ["sharp", "shave"], + "unicode": "🪒" + }, + { + "group": 7, + "hexcode": "1F9F4", + "label": "lotion bottle", + "order": 4439, + "tags": ["bottle", "lotion", "moisturizer", "shampoo", "sunscreen"], + "unicode": "🧴" + }, + { + "group": 7, + "hexcode": "1F9F7", + "label": "safety pin", + "order": 4440, + "tags": ["diaper", "pin", "punk", "rock", "safety"], + "unicode": "🧷" + }, + { + "group": 7, + "hexcode": "1F9F9", + "label": "broom", + "order": 4441, + "tags": ["cleaning", "sweeping", "witch"], + "unicode": "🧹" + }, + { + "group": 7, + "hexcode": "1F9FA", + "label": "basket", + "order": 4442, + "tags": ["farming", "laundry", "picnic"], + "unicode": "🧺" + }, + { + "group": 7, + "hexcode": "1F9FB", + "label": "roll of paper", + "order": 4443, + "tags": ["paper", "roll", "toilet", "towels"], + "unicode": "🧻" + }, + { + "group": 7, + "hexcode": "1FAA3", + "label": "bucket", + "order": 4444, + "tags": ["cask", "pail", "vat"], + "unicode": "🪣" + }, + { + "group": 7, + "hexcode": "1F9FC", + "label": "soap", + "order": 4445, + "tags": ["bar", "bathing", "clean", "cleaning", "lather", "soapdish"], + "unicode": "🧼" + }, + { + "group": 7, + "hexcode": "1FAE7", + "label": "bubbles", + "order": 4446, + "tags": [ + "bubble", + "burp", + "clean", + "floating", + "pearl", + "soap", + "underwater" + ], + "unicode": "🫧" + }, + { + "group": 7, + "hexcode": "1FAA5", + "label": "toothbrush", + "order": 4447, + "tags": [ + "bathroom", + "brush", + "clean", + "dental", + "hygiene", + "teeth", + "toiletry" + ], + "unicode": "🪥" + }, + { + "group": 7, + "hexcode": "1F9FD", + "label": "sponge", + "order": 4448, + "tags": ["absorbing", "cleaning", "porous", "soak"], + "unicode": "🧽" + }, + { + "group": 7, + "hexcode": "1F9EF", + "label": "fire extinguisher", + "order": 4449, + "tags": ["extinguish", "extinguisher", "fire", "quench"], + "unicode": "🧯" + }, + { + "group": 7, + "hexcode": "1F6D2", + "label": "shopping cart", + "order": 4450, + "tags": ["cart", "shopping", "trolley"], + "unicode": "🛒" + }, + { + "group": 7, + "hexcode": "1F6AC", + "label": "cigarette", + "order": 4451, + "tags": ["smoking"], + "unicode": "🚬" + }, + { + "group": 7, + "hexcode": "26B0", + "label": "coffin", + "order": 4453, + "tags": ["dead", "death", "vampire"], + "unicode": "⚰️" + }, + { + "group": 7, + "hexcode": "1FAA6", + "label": "headstone", + "order": 4454, + "tags": [ + "cemetery", + "dead", + "grave", + "graveyard", + "memorial", + "rip", + "tomb", + "tombstone" + ], + "unicode": "🪦" + }, + { + "group": 7, + "hexcode": "26B1", + "label": "funeral urn", + "order": 4456, + "tags": ["ashes", "death", "funeral", "urn"], + "unicode": "⚱️" + }, + { + "group": 7, + "hexcode": "1F9FF", + "label": "nazar amulet", + "order": 4457, + "tags": [ + "amulet", + "bead", + "blue", + "charm", + "evil-eye", + "nazar", + "talisman" + ], + "unicode": "🧿" + }, + { + "group": 7, + "hexcode": "1FAAC", + "label": "hamsa", + "order": 4458, + "tags": [ + "amulet", + "fatima", + "fortune", + "guide", + "hand", + "mary", + "miriam", + "palm", + "protect", + "protection" + ], + "unicode": "🪬" + }, + { + "group": 7, + "hexcode": "1F5FF", + "label": "moai", + "order": 4459, + "tags": ["face", "moyai", "statue", "stoneface", "travel"], + "unicode": "🗿" + }, + { + "group": 7, + "hexcode": "1FAA7", + "label": "placard", + "order": 4460, + "tags": [ + "card", + "demonstration", + "notice", + "picket", + "plaque", + "protest", + "sign" + ], + "unicode": "🪧" + }, + { + "group": 7, + "hexcode": "1FAAA", + "label": "identification card", + "order": 4461, + "tags": [ + "card", + "credentials", + "document", + "id", + "identification", + "license", + "security" + ], + "unicode": "🪪" + } + ] + }, + { + "name": "Symbols", + "emojis": [ + { + "group": 8, + "hexcode": "1F3E7", + "label": "ATM sign", + "order": 4462, + "tags": ["atm", "automated", "bank", "cash", "money", "sign", "teller"], + "unicode": "🏧" + }, + { + "group": 8, + "hexcode": "1F6AE", + "label": "litter in bin sign", + "order": 4463, + "tags": ["bin", "litter", "litterbin", "sign"], + "unicode": "🚮" + }, + { + "group": 8, + "hexcode": "1F6B0", + "label": "potable water", + "order": 4464, + "tags": ["drinking", "potable", "water"], + "unicode": "🚰" + }, + { + "group": 8, + "hexcode": "267F", + "label": "wheelchair symbol", + "order": 4465, + "tags": ["access", "handicap", "symbol", "wheelchair"], + "unicode": "♿️" + }, + { + "group": 8, + "hexcode": "1F6B9", + "label": "men’s room", + "order": 4466, + "tags": [ + "bathroom", + "lavatory", + "man", + "men’s", + "restroom", + "room", + "toilet", + "wc" + ], + "unicode": "🚹️" + }, + { + "group": 8, + "hexcode": "1F6BA", + "label": "women’s room", + "order": 4467, + "tags": [ + "bathroom", + "lavatory", + "restroom", + "room", + "toilet", + "wc", + "woman", + "women’s" + ], + "unicode": "🚺️" + }, + { + "group": 8, + "hexcode": "1F6BB", + "label": "restroom", + "order": 4468, + "tags": ["bathroom", "lavatory", "toilet", "wc"], + "unicode": "🚻" + }, + { + "group": 8, + "hexcode": "1F6BC", + "label": "baby symbol", + "order": 4469, + "tags": ["baby", "changing", "symbol"], + "unicode": "🚼️" + }, + { + "group": 8, + "hexcode": "1F6BE", + "label": "water closet", + "order": 4470, + "tags": [ + "bathroom", + "closet", + "lavatory", + "restroom", + "toilet", + "water", + "wc" + ], + "unicode": "🚾" + }, + { + "group": 8, + "hexcode": "1F6C2", + "label": "passport control", + "order": 4471, + "tags": ["control", "passport"], + "unicode": "🛂" + }, + { + "group": 8, + "hexcode": "1F6C3", + "label": "customs", + "order": 4472, + "tags": ["packing"], + "unicode": "🛃" + }, + { + "group": 8, + "hexcode": "1F6C4", + "label": "baggage claim", + "order": 4473, + "tags": [ + "arrived", + "baggage", + "bags", + "case", + "checked", + "claim", + "journey", + "packing", + "plane", + "ready", + "travel", + "trip" + ], + "unicode": "🛄" + }, + { + "group": 8, + "hexcode": "1F6C5", + "label": "left luggage", + "order": 4474, + "tags": ["baggage", "case", "left", "locker", "luggage"], + "unicode": "🛅" + }, + { + "group": 8, + "hexcode": "26A0", + "label": "warning", + "order": 4476, + "tags": ["caution"], + "unicode": "⚠️" + }, + { + "group": 8, + "hexcode": "1F6B8", + "label": "children crossing", + "order": 4477, + "tags": ["child", "children", "crossing", "pedestrian", "traffic"], + "unicode": "🚸" + }, + { + "group": 8, + "hexcode": "26D4", + "label": "no entry", + "order": 4478, + "tags": [ + "do", + "entry", + "fail", + "forbidden", + "no", + "not", + "pass", + "prohibited", + "traffic" + ], + "unicode": "⛔️" + }, + { + "group": 8, + "hexcode": "1F6AB", + "label": "prohibited", + "order": 4479, + "tags": ["entry", "forbidden", "no", "not", "smoke"], + "unicode": "🚫" + }, + { + "group": 8, + "hexcode": "1F6B3", + "label": "no bicycles", + "order": 4480, + "tags": [ + "bicycle", + "bicycles", + "bike", + "forbidden", + "no", + "not", + "prohibited" + ], + "unicode": "🚳" + }, + { + "group": 8, + "hexcode": "1F6AD", + "label": "no smoking", + "order": 4481, + "tags": ["forbidden", "no", "not", "prohibited", "smoke", "smoking"], + "unicode": "🚭️" + }, + { + "group": 8, + "hexcode": "1F6AF", + "label": "no littering", + "order": 4482, + "tags": ["forbidden", "litter", "littering", "no", "not", "prohibited"], + "unicode": "🚯" + }, + { + "group": 8, + "hexcode": "1F6B1", + "label": "non-potable water", + "order": 4483, + "tags": ["dry", "non-drinking", "non-potable", "prohibited", "water"], + "unicode": "🚱" + }, + { + "group": 8, + "hexcode": "1F6B7", + "label": "no pedestrians", + "order": 4484, + "tags": [ + "forbidden", + "no", + "not", + "pedestrian", + "pedestrians", + "prohibited" + ], + "unicode": "🚷" + }, + { + "group": 8, + "hexcode": "1F4F5", + "label": "no mobile phones", + "order": 4485, + "tags": [ + "cell", + "forbidden", + "mobile", + "no", + "not", + "phone", + "phones", + "prohibited", + "telephone" + ], + "unicode": "📵" + }, + { + "group": 8, + "hexcode": "1F51E", + "label": "no one under eighteen", + "order": 4486, + "tags": [ + "18", + "age", + "eighteen", + "forbidden", + "no", + "not", + "one", + "prohibited", + "restriction", + "underage" + ], + "unicode": "🔞" + }, + { + "group": 8, + "hexcode": "2622", + "label": "radioactive", + "order": 4488, + "tags": ["sign"], + "unicode": "☢️" + }, + { + "group": 8, + "hexcode": "2623", + "label": "biohazard", + "order": 4490, + "tags": ["sign"], + "unicode": "☣️" + }, + { + "group": 8, + "hexcode": "2B06", + "label": "up arrow", + "order": 4492, + "tags": ["arrow", "cardinal", "direction", "north", "up"], + "unicode": "⬆️" + }, + { + "group": 8, + "hexcode": "2197", + "label": "up-right arrow", + "order": 4494, + "tags": [ + "arrow", + "direction", + "intercardinal", + "northeast", + "up-right" + ], + "unicode": "↗️" + }, + { + "group": 8, + "hexcode": "27A1", + "label": "right arrow", + "order": 4496, + "tags": ["arrow", "cardinal", "direction", "east", "right"], + "unicode": "➡️" + }, + { + "group": 8, + "hexcode": "2198", + "label": "down-right arrow", + "order": 4498, + "tags": [ + "arrow", + "direction", + "down-right", + "intercardinal", + "southeast" + ], + "unicode": "↘️" + }, + { + "group": 8, + "hexcode": "2B07", + "label": "down arrow", + "order": 4500, + "tags": ["arrow", "cardinal", "direction", "down", "south"], + "unicode": "⬇️" + }, + { + "group": 8, + "hexcode": "2199", + "label": "down-left arrow", + "order": 4502, + "tags": [ + "arrow", + "direction", + "down-left", + "intercardinal", + "southwest" + ], + "unicode": "↙️" + }, + { + "group": 8, + "hexcode": "2B05", + "label": "left arrow", + "order": 4504, + "tags": ["arrow", "cardinal", "direction", "left", "west"], + "unicode": "⬅️" + }, + { + "group": 8, + "hexcode": "2196", + "label": "up-left arrow", + "order": 4506, + "tags": ["arrow", "direction", "intercardinal", "northwest", "up-left"], + "unicode": "↖️" + }, + { + "group": 8, + "hexcode": "2195", + "label": "up-down arrow", + "order": 4508, + "tags": ["arrow", "up-down"], + "unicode": "↕️" + }, + { + "group": 8, + "hexcode": "2194", + "label": "left-right arrow", + "order": 4510, + "tags": ["arrow", "left-right"], + "unicode": "↔️" + }, + { + "group": 8, + "hexcode": "21A9", + "label": "right arrow curving left", + "order": 4512, + "tags": ["arrow", "curving", "left", "right"], + "unicode": "↩️" + }, + { + "group": 8, + "hexcode": "21AA", + "label": "left arrow curving right", + "order": 4514, + "tags": ["arrow", "curving", "left", "right"], + "unicode": "↪️" + }, + { + "group": 8, + "hexcode": "2934", + "label": "right arrow curving up", + "order": 4516, + "tags": ["arrow", "curving", "right", "up"], + "unicode": "⤴️" + }, + { + "group": 8, + "hexcode": "2935", + "label": "right arrow curving down", + "order": 4518, + "tags": ["arrow", "curving", "down", "right"], + "unicode": "⤵️" + }, + { + "group": 8, + "hexcode": "1F503", + "label": "clockwise vertical arrows", + "order": 4519, + "tags": [ + "arrow", + "arrows", + "clockwise", + "refresh", + "reload", + "vertical" + ], + "unicode": "🔃" + }, + { + "group": 8, + "hexcode": "1F504", + "label": "counterclockwise arrows button", + "order": 4520, + "tags": [ + "again", + "anticlockwise", + "arrow", + "arrows", + "button", + "counterclockwise", + "deja", + "refresh", + "rewindershins", + "vu" + ], + "unicode": "🔄" + }, + { + "group": 8, + "hexcode": "1F519", + "label": "BACK arrow", + "order": 4521, + "tags": ["arrow", "back"], + "unicode": "🔙" + }, + { + "group": 8, + "hexcode": "1F51A", + "label": "END arrow", + "order": 4522, + "tags": ["arrow", "end"], + "unicode": "🔚" + }, + { + "group": 8, + "hexcode": "1F51B", + "label": "ON! arrow", + "order": 4523, + "tags": ["arrow", "mark", "on!"], + "unicode": "🔛" + }, + { + "group": 8, + "hexcode": "1F51C", + "label": "SOON arrow", + "order": 4524, + "tags": ["arrow", "brb", "omw", "soon"], + "unicode": "🔜" + }, + { + "group": 8, + "hexcode": "1F51D", + "label": "TOP arrow", + "order": 4525, + "tags": ["arrow", "homie", "top", "up"], + "unicode": "🔝" + }, + { + "group": 8, + "hexcode": "1F6D0", + "label": "place of worship", + "order": 4526, + "tags": ["place", "pray", "religion", "worship"], + "unicode": "🛐" + }, + { + "group": 8, + "hexcode": "269B", + "label": "atom symbol", + "order": 4528, + "tags": ["atheist", "atom", "symbol"], + "unicode": "⚛️" + }, + { + "group": 8, + "hexcode": "1F549", + "label": "om", + "order": 4530, + "tags": ["hindu", "religion"], + "unicode": "🕉️" + }, + { + "group": 8, + "hexcode": "2721", + "label": "star of David", + "order": 4532, + "tags": ["david", "jew", "jewish", "judaism", "religion", "star"], + "unicode": "✡️" + }, + { + "group": 8, + "hexcode": "2638", + "label": "wheel of dharma", + "order": 4534, + "tags": ["buddhist", "dharma", "religion", "wheel"], + "unicode": "☸️" + }, + { + "group": 8, + "hexcode": "262F", + "label": "yin yang", + "order": 4536, + "tags": [ + "difficult", + "lives", + "religion", + "tao", + "taoist", + "total", + "yang", + "yin", + "yinyang" + ], + "unicode": "☯️" + }, + { + "group": 8, + "hexcode": "271D", + "label": "latin cross", + "order": 4538, + "tags": ["christ", "christian", "cross", "latin", "religion"], + "unicode": "✝️" + }, + { + "group": 8, + "hexcode": "2626", + "label": "orthodox cross", + "order": 4540, + "tags": ["christian", "cross", "orthodox", "religion"], + "unicode": "☦️" + }, + { + "group": 8, + "hexcode": "262A", + "label": "star and crescent", + "order": 4542, + "tags": ["crescent", "islam", "muslim", "ramadan", "religion", "star"], + "unicode": "☪️" + }, + { + "group": 8, + "hexcode": "262E", + "label": "peace symbol", + "order": 4544, + "tags": ["healing", "peace", "peaceful", "symbol"], + "unicode": "☮️" + }, + { + "group": 8, + "hexcode": "1F54E", + "label": "menorah", + "order": 4545, + "tags": [ + "candelabrum", + "candlestick", + "hanukkah", + "jewish", + "judaism", + "religion" + ], + "unicode": "🕎" + }, + { + "group": 8, + "hexcode": "1F52F", + "label": "dotted six-pointed star", + "order": 4546, + "tags": [ + "dotted", + "fortune", + "jewish", + "judaism", + "six-pointed", + "star" + ], + "unicode": "🔯" + }, + { + "group": 8, + "hexcode": "1FAAF", + "label": "khanda", + "order": 4547, + "tags": [ + "deg", + "fateh", + "khalsa", + "religion", + "sikh", + "sikhism", + "tegh" + ], + "unicode": "🪯" + }, + { + "group": 8, + "hexcode": "2648", + "label": "Aries", + "order": 4548, + "tags": ["aries", "horoscope", "ram", "zodiac"], + "unicode": "♈️" + }, + { + "group": 8, + "hexcode": "2649", + "label": "Taurus", + "order": 4549, + "tags": ["bull", "horoscope", "ox", "taurus", "zodiac"], + "unicode": "♉️" + }, + { + "group": 8, + "hexcode": "264A", + "label": "Gemini", + "order": 4550, + "tags": ["gemini", "horoscope", "twins", "zodiac"], + "unicode": "♊️" + }, + { + "group": 8, + "hexcode": "264B", + "label": "Cancer", + "order": 4551, + "tags": ["cancer", "crab", "horoscope", "zodiac"], + "unicode": "♋️" + }, + { + "group": 8, + "hexcode": "264C", + "label": "Leo", + "order": 4552, + "tags": ["horoscope", "leo", "lion", "zodiac"], + "unicode": "♌️" + }, + { + "group": 8, + "hexcode": "264D", + "label": "Virgo", + "order": 4553, + "tags": ["horoscope", "virgo", "zodiac"], + "unicode": "♍️" + }, + { + "group": 8, + "hexcode": "264E", + "label": "Libra", + "order": 4554, + "tags": [ + "balance", + "horoscope", + "justice", + "libra", + "scales", + "zodiac" + ], + "unicode": "♎️" + }, + { + "group": 8, + "hexcode": "264F", + "label": "Scorpio", + "order": 4555, + "tags": ["horoscope", "scorpio", "scorpion", "scorpius", "zodiac"], + "unicode": "♏️" + }, + { + "group": 8, + "hexcode": "2650", + "label": "Sagittarius", + "order": 4556, + "tags": ["archer", "horoscope", "sagittarius", "zodiac"], + "unicode": "♐️" + }, + { + "group": 8, + "hexcode": "2651", + "label": "Capricorn", + "order": 4557, + "tags": ["capricorn", "goat", "horoscope", "zodiac"], + "unicode": "♑️" + }, + { + "group": 8, + "hexcode": "2652", + "label": "Aquarius", + "order": 4558, + "tags": ["aquarius", "bearer", "horoscope", "water", "zodiac"], + "unicode": "♒️" + }, + { + "group": 8, + "hexcode": "2653", + "label": "Pisces", + "order": 4559, + "tags": ["fish", "horoscope", "pisces", "zodiac"], + "unicode": "♓️" + }, + { + "group": 8, + "hexcode": "26CE", + "label": "Ophiuchus", + "order": 4560, + "tags": ["bearer", "ophiuchus", "serpent", "snake", "zodiac"], + "unicode": "⛎️" + }, + { + "group": 8, + "hexcode": "1F500", + "label": "shuffle tracks button", + "order": 4561, + "tags": ["arrow", "button", "crossed", "shuffle", "tracks"], + "unicode": "🔀" + }, + { + "group": 8, + "hexcode": "1F501", + "label": "repeat button", + "order": 4562, + "tags": ["arrow", "button", "clockwise", "repeat"], + "unicode": "🔁" + }, + { + "group": 8, + "hexcode": "1F502", + "label": "repeat single button", + "order": 4563, + "tags": ["arrow", "button", "clockwise", "once", "repeat", "single"], + "unicode": "🔂" + }, + { + "group": 8, + "hexcode": "25B6", + "label": "play button", + "order": 4565, + "tags": ["arrow", "button", "play", "right", "triangle"], + "unicode": "▶️" + }, + { + "group": 8, + "hexcode": "23E9", + "label": "fast-forward button", + "order": 4566, + "tags": [ + "arrow", + "button", + "double", + "fast", + "fast-forward", + "forward" + ], + "unicode": "⏩️" + }, + { + "group": 8, + "hexcode": "23ED", + "label": "next track button", + "order": 4568, + "tags": ["arrow", "button", "next", "scene", "track", "triangle"], + "unicode": "⏭️" + }, + { + "group": 8, + "hexcode": "23EF", + "label": "play or pause button", + "order": 4570, + "tags": ["arrow", "button", "pause", "play", "right", "triangle"], + "unicode": "⏯️" + }, + { + "group": 8, + "hexcode": "25C0", + "label": "reverse button", + "order": 4572, + "tags": ["arrow", "button", "left", "reverse", "triangle"], + "unicode": "◀️" + }, + { + "group": 8, + "hexcode": "23EA", + "label": "fast reverse button", + "order": 4573, + "tags": ["arrow", "button", "double", "fast", "reverse", "rewind"], + "unicode": "⏪️" + }, + { + "group": 8, + "hexcode": "23EE", + "label": "last track button", + "order": 4575, + "tags": [ + "arrow", + "button", + "last", + "previous", + "scene", + "track", + "triangle" + ], + "unicode": "⏮️" + }, + { + "group": 8, + "hexcode": "1F53C", + "label": "upwards button", + "order": 4576, + "tags": ["arrow", "button", "red", "up", "upwards"], + "unicode": "🔼" + }, + { + "group": 8, + "hexcode": "23EB", + "label": "fast up button", + "order": 4577, + "tags": ["arrow", "button", "double", "fast", "up"], + "unicode": "⏫️" + }, + { + "group": 8, + "hexcode": "1F53D", + "label": "downwards button", + "order": 4578, + "tags": ["arrow", "button", "down", "downwards", "red"], + "unicode": "🔽" + }, + { + "group": 8, + "hexcode": "23EC", + "label": "fast down button", + "order": 4579, + "tags": ["arrow", "button", "double", "down", "fast"], + "unicode": "⏬️" + }, + { + "group": 8, + "hexcode": "23F8", + "label": "pause button", + "order": 4581, + "tags": ["bar", "button", "double", "pause", "vertical"], + "unicode": "⏸️" + }, + { + "group": 8, + "hexcode": "23F9", + "label": "stop button", + "order": 4583, + "tags": ["button", "square", "stop"], + "unicode": "⏹️" + }, + { + "group": 8, + "hexcode": "23FA", + "label": "record button", + "order": 4585, + "tags": ["button", "circle", "record"], + "unicode": "⏺️" + }, + { + "group": 8, + "hexcode": "23CF", + "label": "eject button", + "order": 4587, + "tags": ["button", "eject"], + "unicode": "⏏️" + }, + { + "group": 8, + "hexcode": "1F3A6", + "label": "cinema", + "order": 4588, + "tags": ["camera", "film", "movie"], + "unicode": "🎦" + }, + { + "group": 8, + "hexcode": "1F505", + "label": "dim button", + "order": 4589, + "tags": ["brightness", "button", "dim", "low"], + "unicode": "🔅" + }, + { + "group": 8, + "hexcode": "1F506", + "label": "bright button", + "order": 4590, + "tags": ["bright", "brightness", "button", "light"], + "unicode": "🔆" + }, + { + "group": 8, + "hexcode": "1F4F6", + "label": "antenna bars", + "order": 4591, + "tags": [ + "antenna", + "bar", + "bars", + "cell", + "communication", + "mobile", + "phone", + "signal", + "telephone" + ], + "unicode": "📶" + }, + { + "group": 8, + "hexcode": "1F6DC", + "label": "wireless", + "order": 4592, + "tags": [ + "broadband", + "computer", + "connectivity", + "hotspot", + "internet", + "network", + "router", + "smartphone", + "wi-fi", + "wifi", + "wlan" + ], + "unicode": "🛜" + }, + { + "group": 8, + "hexcode": "1F4F3", + "label": "vibration mode", + "order": 4593, + "tags": [ + "cell", + "communication", + "mobile", + "mode", + "phone", + "telephone", + "vibration" + ], + "unicode": "📳" + }, + { + "group": 8, + "hexcode": "1F4F4", + "label": "mobile phone off", + "order": 4594, + "tags": ["cell", "mobile", "off", "phone", "telephone"], + "unicode": "📴" + }, + { + "group": 8, + "hexcode": "2640", + "label": "female sign", + "order": 4596, + "tags": ["female", "sign", "woman"], + "unicode": "♀️" + }, + { + "group": 8, + "hexcode": "2642", + "label": "male sign", + "order": 4598, + "tags": ["male", "man", "sign"], + "unicode": "♂️" + }, + { + "group": 8, + "hexcode": "26A7", + "label": "transgender symbol", + "order": 4600, + "tags": ["symbol", "transgender"], + "unicode": "⚧️" + }, + { + "group": 8, + "hexcode": "2716", + "label": "multiply", + "order": 4602, + "tags": ["cancel", "multiplication", "sign", "x", "×"], + "unicode": "✖️" + }, + { + "group": 8, + "hexcode": "2795", + "label": "plus", + "order": 4603, + "tags": ["+"], + "unicode": "➕️" + }, + { + "group": 8, + "hexcode": "2796", + "label": "minus", + "order": 4604, + "tags": ["-", "heavy", "math", "sign", "−"], + "unicode": "➖️" + }, + { + "group": 8, + "hexcode": "2797", + "label": "divide", + "order": 4605, + "tags": ["division", "heavy", "math", "sign", "÷"], + "unicode": "➗️" + }, + { + "group": 8, + "hexcode": "1F7F0", + "label": "heavy equals sign", + "order": 4606, + "tags": [ + "answer", + "equal", + "equality", + "equals", + "heavy", + "math", + "sign" + ], + "unicode": "🟰" + }, + { + "group": 8, + "hexcode": "267E", + "label": "infinity", + "order": 4608, + "tags": ["forever", "unbounded", "universal"], + "unicode": "♾️" + }, + { + "group": 8, + "hexcode": "203C", + "label": "double exclamation mark", + "order": 4610, + "tags": [ + "!", + "!!", + "bangbang", + "double", + "exclamation", + "mark", + "punctuation" + ], + "unicode": "‼️" + }, + { + "group": 8, + "hexcode": "2049", + "label": "exclamation question mark", + "order": 4612, + "tags": [ + "!", + "!?", + "?", + "exclamation", + "interrobang", + "mark", + "punctuation", + "question" + ], + "unicode": "⁉️" + }, + { + "group": 8, + "hexcode": "2753", + "label": "red question mark", + "order": 4613, + "tags": ["?", "mark", "punctuation", "question", "red"], + "unicode": "❓️" + }, + { + "group": 8, + "hexcode": "2754", + "label": "white question mark", + "order": 4614, + "tags": ["?", "mark", "outlined", "punctuation", "question", "white"], + "unicode": "❔️" + }, + { + "group": 8, + "hexcode": "2755", + "label": "white exclamation mark", + "order": 4615, + "tags": [ + "!", + "exclamation", + "mark", + "outlined", + "punctuation", + "white" + ], + "unicode": "❕️" + }, + { + "group": 8, + "hexcode": "2757", + "label": "red exclamation mark", + "order": 4616, + "tags": ["!", "exclamation", "mark", "punctuation", "red"], + "unicode": "❗️" + }, + { + "group": 8, + "hexcode": "3030", + "label": "wavy dash", + "order": 4618, + "tags": ["dash", "punctuation", "wavy"], + "unicode": "〰️" + }, + { + "group": 8, + "hexcode": "1F4B1", + "label": "currency exchange", + "order": 4619, + "tags": ["bank", "currency", "exchange", "money"], + "unicode": "💱" + }, + { + "group": 8, + "hexcode": "1F4B2", + "label": "heavy dollar sign", + "order": 4620, + "tags": [ + "billion", + "cash", + "charge", + "currency", + "dollar", + "heavy", + "million", + "money", + "pay", + "sign" + ], + "unicode": "💲" + }, + { + "group": 8, + "hexcode": "2695", + "label": "medical symbol", + "order": 4622, + "tags": ["aesculapius", "medical", "medicine", "staff", "symbol"], + "unicode": "⚕️" + }, + { + "group": 8, + "hexcode": "267B", + "label": "recycling symbol", + "order": 4624, + "tags": ["recycle", "recycling", "symbol"], + "unicode": "♻️" + }, + { + "group": 8, + "hexcode": "269C", + "label": "fleur-de-lis", + "order": 4626, + "tags": ["knights"], + "unicode": "⚜️" + }, + { + "group": 8, + "hexcode": "1F531", + "label": "trident emblem", + "order": 4627, + "tags": ["anchor", "emblem", "poseidon", "ship", "tool", "trident"], + "unicode": "🔱" + }, + { + "group": 8, + "hexcode": "1F4DB", + "label": "name badge", + "order": 4628, + "tags": ["badge", "name"], + "unicode": "📛" + }, + { + "group": 8, + "hexcode": "1F530", + "label": "Japanese symbol for beginner", + "order": 4629, + "tags": [ + "beginner", + "chevron", + "green", + "japanese", + "leaf", + "symbol", + "tool", + "yellow" + ], + "unicode": "🔰" + }, + { + "group": 8, + "hexcode": "2B55", + "label": "hollow red circle", + "order": 4630, + "tags": ["circle", "heavy", "hollow", "large", "o", "red"], + "unicode": "⭕️" + }, + { + "group": 8, + "hexcode": "2705", + "label": "check mark button", + "order": 4631, + "tags": [ + "button", + "check", + "checked", + "checkmark", + "complete", + "completed", + "done", + "fixed", + "mark", + "tick", + "✓" + ], + "unicode": "✅️" + }, + { + "group": 8, + "hexcode": "2611", + "label": "check box with check", + "order": 4633, + "tags": [ + "ballot", + "box", + "check", + "checked", + "done", + "off", + "tick", + "✓" + ], + "unicode": "☑️" + }, + { + "group": 8, + "hexcode": "2714", + "label": "check mark", + "order": 4635, + "tags": [ + "check", + "checked", + "checkmark", + "done", + "heavy", + "mark", + "tick", + "✓" + ], + "unicode": "✔️" + }, + { + "group": 8, + "hexcode": "274C", + "label": "cross mark", + "order": 4636, + "tags": [ + "cancel", + "cross", + "mark", + "multiplication", + "multiply", + "x", + "×" + ], + "unicode": "❌️" + }, + { + "group": 8, + "hexcode": "274E", + "label": "cross mark button", + "order": 4637, + "tags": [ + "button", + "cross", + "mark", + "multiplication", + "multiply", + "square", + "x", + "×" + ], + "unicode": "❎️" + }, + { + "group": 8, + "hexcode": "27B0", + "label": "curly loop", + "order": 4638, + "tags": ["curl", "curly", "loop"], + "unicode": "➰️" + }, + { + "group": 8, + "hexcode": "27BF", + "label": "double curly loop", + "order": 4639, + "tags": ["curl", "curly", "double", "loop"], + "unicode": "➿️" + }, + { + "group": 8, + "hexcode": "303D", + "label": "part alternation mark", + "order": 4641, + "tags": ["alternation", "mark", "part"], + "unicode": "〽️" + }, + { + "group": 8, + "hexcode": "2733", + "label": "eight-spoked asterisk", + "order": 4643, + "tags": ["*", "asterisk", "eight-spoked"], + "unicode": "✳️" + }, + { + "group": 8, + "hexcode": "2734", + "label": "eight-pointed star", + "order": 4645, + "tags": ["*", "eight-pointed", "star"], + "unicode": "✴️" + }, + { + "group": 8, + "hexcode": "2747", + "label": "sparkle", + "order": 4647, + "tags": ["*"], + "unicode": "❇️" + }, + { + "group": 8, + "hexcode": "00A9", + "label": "copyright", + "order": 4649, + "tags": ["c"], + "unicode": "©️" + }, + { + "group": 8, + "hexcode": "00AE", + "label": "registered", + "order": 4651, + "tags": ["r"], + "unicode": "®️" + }, + { + "group": 8, + "hexcode": "2122", + "label": "trade mark", + "order": 4653, + "tags": ["mark", "tm", "trade", "trademark"], + "unicode": "™️" + }, + { + "group": 8, + "hexcode": "1FADF", + "label": "splatter", + "order": 4654, + "tags": [ + "drip", + "holi", + "ink", + "liquid", + "mess", + "paint", + "spill", + "stain" + ], + "unicode": "🫟" + }, + { + "group": 8, + "hexcode": "0023-FE0F-20E3", + "label": "keycap: #", + "order": 4655, + "tags": ["keycap"], + "unicode": "#️⃣" + }, + { + "group": 8, + "hexcode": "002A-FE0F-20E3", + "label": "keycap: *", + "order": 4657, + "tags": ["keycap"], + "unicode": "*️⃣" + }, + { + "group": 8, + "hexcode": "0030-FE0F-20E3", + "label": "keycap: 0", + "order": 4659, + "tags": ["keycap"], + "unicode": "0️⃣" + }, + { + "group": 8, + "hexcode": "0031-FE0F-20E3", + "label": "keycap: 1", + "order": 4661, + "tags": ["keycap"], + "unicode": "1️⃣" + }, + { + "group": 8, + "hexcode": "0032-FE0F-20E3", + "label": "keycap: 2", + "order": 4663, + "tags": ["keycap"], + "unicode": "2️⃣" + }, + { + "group": 8, + "hexcode": "0033-FE0F-20E3", + "label": "keycap: 3", + "order": 4665, + "tags": ["keycap"], + "unicode": "3️⃣" + }, + { + "group": 8, + "hexcode": "0034-FE0F-20E3", + "label": "keycap: 4", + "order": 4667, + "tags": ["keycap"], + "unicode": "4️⃣" + }, + { + "group": 8, + "hexcode": "0035-FE0F-20E3", + "label": "keycap: 5", + "order": 4669, + "tags": ["keycap"], + "unicode": "5️⃣" + }, + { + "group": 8, + "hexcode": "0036-FE0F-20E3", + "label": "keycap: 6", + "order": 4671, + "tags": ["keycap"], + "unicode": "6️⃣" + }, + { + "group": 8, + "hexcode": "0037-FE0F-20E3", + "label": "keycap: 7", + "order": 4673, + "tags": ["keycap"], + "unicode": "7️⃣" + }, + { + "group": 8, + "hexcode": "0038-FE0F-20E3", + "label": "keycap: 8", + "order": 4675, + "tags": ["keycap"], + "unicode": "8️⃣" + }, + { + "group": 8, + "hexcode": "0039-FE0F-20E3", + "label": "keycap: 9", + "order": 4677, + "tags": ["keycap"], + "unicode": "9️⃣" + }, + { + "group": 8, + "hexcode": "1F51F", + "label": "keycap: 10", + "order": 4679, + "tags": ["keycap"], + "unicode": "🔟" + }, + { + "group": 8, + "hexcode": "1F520", + "label": "input latin uppercase", + "order": 4680, + "tags": ["abcd", "input", "latin", "letters", "uppercase"], + "unicode": "🔠" + }, + { + "group": 8, + "hexcode": "1F521", + "label": "input latin lowercase", + "order": 4681, + "tags": ["abcd", "input", "latin", "letters", "lowercase"], + "unicode": "🔡" + }, + { + "group": 8, + "hexcode": "1F522", + "label": "input numbers", + "order": 4682, + "tags": ["1234", "input", "numbers"], + "unicode": "🔢" + }, + { + "group": 8, + "hexcode": "1F523", + "label": "input symbols", + "order": 4683, + "tags": ["%", "&", "input", "symbols", "♪", "〒"], + "unicode": "🔣" + }, + { + "group": 8, + "hexcode": "1F524", + "label": "input latin letters", + "order": 4684, + "tags": ["abc", "alphabet", "input", "latin", "letters"], + "unicode": "🔤" + }, + { + "group": 8, + "hexcode": "1F170", + "label": "A button (blood type)", + "order": 4686, + "tags": ["blood", "button", "type"], + "unicode": "🅰️" + }, + { + "group": 8, + "hexcode": "1F18E", + "label": "AB button (blood type)", + "order": 4687, + "tags": ["ab", "blood", "button", "type"], + "unicode": "🆎" + }, + { + "group": 8, + "hexcode": "1F171", + "label": "B button (blood type)", + "order": 4689, + "tags": ["b", "blood", "button", "type"], + "unicode": "🅱️" + }, + { + "group": 8, + "hexcode": "1F191", + "label": "CL button", + "order": 4690, + "tags": ["button", "cl"], + "unicode": "🆑" + }, + { + "group": 8, + "hexcode": "1F192", + "label": "COOL button", + "order": 4691, + "tags": ["button", "cool"], + "unicode": "🆒" + }, + { + "group": 8, + "hexcode": "1F193", + "label": "FREE button", + "order": 4692, + "tags": ["button", "free"], + "unicode": "🆓" + }, + { + "group": 8, + "hexcode": "2139", + "label": "information", + "order": 4694, + "tags": ["i"], + "unicode": "ℹ️" + }, + { + "group": 8, + "hexcode": "1F194", + "label": "ID button", + "order": 4695, + "tags": ["button", "id", "identity"], + "unicode": "🆔" + }, + { + "group": 8, + "hexcode": "24C2", + "label": "circled M", + "order": 4697, + "tags": ["circle", "circled", "m"], + "unicode": "Ⓜ️" + }, + { + "group": 8, + "hexcode": "1F195", + "label": "NEW button", + "order": 4698, + "tags": ["button", "new"], + "unicode": "🆕" + }, + { + "group": 8, + "hexcode": "1F196", + "label": "NG button", + "order": 4699, + "tags": ["button", "ng"], + "unicode": "🆖" + }, + { + "group": 8, + "hexcode": "1F17E", + "label": "O button (blood type)", + "order": 4701, + "tags": ["blood", "button", "o", "type"], + "unicode": "🅾️" + }, + { + "group": 8, + "hexcode": "1F197", + "label": "OK button", + "order": 4702, + "tags": ["button", "ok", "okay"], + "unicode": "🆗" + }, + { + "group": 8, + "hexcode": "1F17F", + "label": "P button", + "order": 4704, + "tags": ["button", "p", "parking"], + "unicode": "🅿️" + }, + { + "group": 8, + "hexcode": "1F198", + "label": "SOS button", + "order": 4705, + "tags": ["button", "help", "sos"], + "unicode": "🆘" + }, + { + "group": 8, + "hexcode": "1F199", + "label": "UP! button", + "order": 4706, + "tags": ["button", "mark", "up", "up!"], + "unicode": "🆙" + }, + { + "group": 8, + "hexcode": "1F19A", + "label": "VS button", + "order": 4707, + "tags": ["button", "versus", "vs"], + "unicode": "🆚" + }, + { + "group": 8, + "hexcode": "1F201", + "label": "Japanese “here” button", + "order": 4708, + "tags": ["button", "here", "japanese", "katakana"], + "unicode": "🈁" + }, + { + "group": 8, + "hexcode": "1F202", + "label": "Japanese “service charge” button", + "order": 4710, + "tags": ["button", "charge", "japanese", "katakana", "service"], + "unicode": "🈂️" + }, + { + "group": 8, + "hexcode": "1F237", + "label": "Japanese “monthly amount” button", + "order": 4712, + "tags": ["amount", "button", "ideograph", "japanese", "monthly"], + "unicode": "🈷️" + }, + { + "group": 8, + "hexcode": "1F236", + "label": "Japanese “not free of charge” button", + "order": 4713, + "tags": ["button", "charge", "free", "ideograph", "japanese", "not"], + "unicode": "🈶" + }, + { + "group": 8, + "hexcode": "1F22F", + "label": "Japanese “reserved” button", + "order": 4714, + "tags": ["button", "ideograph", "japanese", "reserved"], + "unicode": "🈯️" + }, + { + "group": 8, + "hexcode": "1F250", + "label": "Japanese “bargain” button", + "order": 4715, + "tags": ["bargain", "button", "ideograph", "japanese"], + "unicode": "🉐" + }, + { + "group": 8, + "hexcode": "1F239", + "label": "Japanese “discount” button", + "order": 4716, + "tags": ["button", "discount", "ideograph", "japanese"], + "unicode": "🈹" + }, + { + "group": 8, + "hexcode": "1F21A", + "label": "Japanese “free of charge” button", + "order": 4717, + "tags": ["button", "charge", "free", "ideograph", "japanese"], + "unicode": "🈚️" + }, + { + "group": 8, + "hexcode": "1F232", + "label": "Japanese “prohibited” button", + "order": 4718, + "tags": ["button", "ideograph", "japanese", "prohibited"], + "unicode": "🈲" + }, + { + "group": 8, + "hexcode": "1F251", + "label": "Japanese “acceptable” button", + "order": 4719, + "tags": ["acceptable", "button", "ideograph", "japanese"], + "unicode": "🉑" + }, + { + "group": 8, + "hexcode": "1F238", + "label": "Japanese “application” button", + "order": 4720, + "tags": ["application", "button", "ideograph", "japanese"], + "unicode": "🈸" + }, + { + "group": 8, + "hexcode": "1F234", + "label": "Japanese “passing grade” button", + "order": 4721, + "tags": ["button", "grade", "ideograph", "japanese", "passing"], + "unicode": "🈴" + }, + { + "group": 8, + "hexcode": "1F233", + "label": "Japanese “vacancy” button", + "order": 4722, + "tags": ["button", "ideograph", "japanese", "vacancy"], + "unicode": "🈳" + }, + { + "group": 8, + "hexcode": "3297", + "label": "Japanese “congratulations” button", + "order": 4724, + "tags": ["button", "congratulations", "ideograph", "japanese"], + "unicode": "㊗️" + }, + { + "group": 8, + "hexcode": "3299", + "label": "Japanese “secret” button", + "order": 4726, + "tags": ["button", "ideograph", "japanese", "secret"], + "unicode": "㊙️" + }, + { + "group": 8, + "hexcode": "1F23A", + "label": "Japanese “open for business” button", + "order": 4727, + "tags": ["business", "button", "ideograph", "japanese", "open"], + "unicode": "🈺" + }, + { + "group": 8, + "hexcode": "1F235", + "label": "Japanese “no vacancy” button", + "order": 4728, + "tags": ["button", "ideograph", "japanese", "no", "vacancy"], + "unicode": "🈵" + }, + { + "group": 8, + "hexcode": "1F534", + "label": "red circle", + "order": 4729, + "tags": ["circle", "geometric", "red"], + "unicode": "🔴" + }, + { + "group": 8, + "hexcode": "1F7E0", + "label": "orange circle", + "order": 4730, + "tags": ["circle", "orange"], + "unicode": "🟠" + }, + { + "group": 8, + "hexcode": "1F7E1", + "label": "yellow circle", + "order": 4731, + "tags": ["circle", "yellow"], + "unicode": "🟡" + }, + { + "group": 8, + "hexcode": "1F7E2", + "label": "green circle", + "order": 4732, + "tags": ["circle", "green"], + "unicode": "🟢" + }, + { + "group": 8, + "hexcode": "1F535", + "label": "blue circle", + "order": 4733, + "tags": ["blue", "circle", "geometric"], + "unicode": "🔵" + }, + { + "group": 8, + "hexcode": "1F7E3", + "label": "purple circle", + "order": 4734, + "tags": ["circle", "purple"], + "unicode": "🟣" + }, + { + "group": 8, + "hexcode": "1F7E4", + "label": "brown circle", + "order": 4735, + "tags": ["brown", "circle"], + "unicode": "🟤" + }, + { + "group": 8, + "hexcode": "26AB", + "label": "black circle", + "order": 4736, + "tags": ["black", "circle", "geometric"], + "unicode": "⚫️" + }, + { + "group": 8, + "hexcode": "26AA", + "label": "white circle", + "order": 4737, + "tags": ["circle", "geometric", "white"], + "unicode": "⚪️" + }, + { + "group": 8, + "hexcode": "1F7E5", + "label": "red square", + "order": 4738, + "tags": ["card", "penalty", "red", "square"], + "unicode": "🟥" + }, + { + "group": 8, + "hexcode": "1F7E7", + "label": "orange square", + "order": 4739, + "tags": ["orange", "square"], + "unicode": "🟧" + }, + { + "group": 8, + "hexcode": "1F7E8", + "label": "yellow square", + "order": 4740, + "tags": ["card", "penalty", "square", "yellow"], + "unicode": "🟨" + }, + { + "group": 8, + "hexcode": "1F7E9", + "label": "green square", + "order": 4741, + "tags": ["green", "square"], + "unicode": "🟩" + }, + { + "group": 8, + "hexcode": "1F7E6", + "label": "blue square", + "order": 4742, + "tags": ["blue", "square"], + "unicode": "🟦" + }, + { + "group": 8, + "hexcode": "1F7EA", + "label": "purple square", + "order": 4743, + "tags": ["purple", "square"], + "unicode": "🟪" + }, + { + "group": 8, + "hexcode": "1F7EB", + "label": "brown square", + "order": 4744, + "tags": ["brown", "square"], + "unicode": "🟫" + }, + { + "group": 8, + "hexcode": "2B1B", + "label": "black large square", + "order": 4745, + "tags": ["black", "geometric", "large", "square"], + "unicode": "⬛️" + }, + { + "group": 8, + "hexcode": "2B1C", + "label": "white large square", + "order": 4746, + "tags": ["geometric", "large", "square", "white"], + "unicode": "⬜️" + }, + { + "group": 8, + "hexcode": "25FC", + "label": "black medium square", + "order": 4748, + "tags": ["black", "geometric", "medium", "square"], + "unicode": "◼️" + }, + { + "group": 8, + "hexcode": "25FB", + "label": "white medium square", + "order": 4750, + "tags": ["geometric", "medium", "square", "white"], + "unicode": "◻️" + }, + { + "group": 8, + "hexcode": "25FE", + "label": "black medium-small square", + "order": 4751, + "tags": ["black", "geometric", "medium-small", "square"], + "unicode": "◾️" + }, + { + "group": 8, + "hexcode": "25FD", + "label": "white medium-small square", + "order": 4752, + "tags": ["geometric", "medium-small", "square", "white"], + "unicode": "◽️" + }, + { + "group": 8, + "hexcode": "25AA", + "label": "black small square", + "order": 4754, + "tags": ["black", "geometric", "small", "square"], + "unicode": "▪️" + }, + { + "group": 8, + "hexcode": "25AB", + "label": "white small square", + "order": 4756, + "tags": ["geometric", "small", "square", "white"], + "unicode": "▫️" + }, + { + "group": 8, + "hexcode": "1F536", + "label": "large orange diamond", + "order": 4757, + "tags": ["diamond", "geometric", "large", "orange"], + "unicode": "🔶" + }, + { + "group": 8, + "hexcode": "1F537", + "label": "large blue diamond", + "order": 4758, + "tags": ["blue", "diamond", "geometric", "large"], + "unicode": "🔷" + }, + { + "group": 8, + "hexcode": "1F538", + "label": "small orange diamond", + "order": 4759, + "tags": ["diamond", "geometric", "orange", "small"], + "unicode": "🔸" + }, + { + "group": 8, + "hexcode": "1F539", + "label": "small blue diamond", + "order": 4760, + "tags": ["blue", "diamond", "geometric", "small"], + "unicode": "🔹" + }, + { + "group": 8, + "hexcode": "1F53A", + "label": "red triangle pointed up", + "order": 4761, + "tags": ["geometric", "pointed", "red", "triangle", "up"], + "unicode": "🔺" + }, + { + "group": 8, + "hexcode": "1F53B", + "label": "red triangle pointed down", + "order": 4762, + "tags": ["down", "geometric", "pointed", "red", "triangle"], + "unicode": "🔻" + }, + { + "group": 8, + "hexcode": "1F4A0", + "label": "diamond with a dot", + "order": 4763, + "tags": ["comic", "diamond", "dot", "geometric"], + "unicode": "💠" + }, + { + "group": 8, + "hexcode": "1F518", + "label": "radio button", + "order": 4764, + "tags": ["button", "geometric", "radio"], + "unicode": "🔘" + }, + { + "group": 8, + "hexcode": "1F533", + "label": "white square button", + "order": 4765, + "tags": ["button", "geometric", "outlined", "square", "white"], + "unicode": "🔳" + }, + { + "group": 8, + "hexcode": "1F532", + "label": "black square button", + "order": 4766, + "tags": ["black", "button", "geometric", "square"], + "unicode": "🔲" + } + ] + }, + { + "name": "Flags", + "emojis": [ + { + "group": 9, + "hexcode": "1F3C1", + "label": "chequered flag", + "order": 4767, + "tags": [ + "checkered", + "chequered", + "finish", + "flag", + "flags", + "game", + "race", + "racing", + "sport", + "win" + ], + "unicode": "🏁" + }, + { + "group": 9, + "hexcode": "1F6A9", + "label": "triangular flag", + "order": 4768, + "tags": ["construction", "flag", "golf", "post", "triangular"], + "unicode": "🚩" + }, + { + "group": 9, + "hexcode": "1F38C", + "label": "crossed flags", + "order": 4769, + "tags": ["celebration", "cross", "crossed", "flags", "japanese"], + "unicode": "🎌" + }, + { + "group": 9, + "hexcode": "1F3F4", + "label": "black flag", + "order": 4770, + "tags": ["black", "flag", "waving"], + "unicode": "🏴" + }, + { + "group": 9, + "hexcode": "1F3F3", + "label": "white flag", + "order": 4772, + "tags": ["flag", "waving", "white"], + "unicode": "🏳️" + }, + { + "group": 9, + "hexcode": "1F3F3-FE0F-200D-1F308", + "label": "rainbow flag", + "order": 4773, + "tags": [ + "bisexual", + "flag", + "gay", + "genderqueer", + "glbt", + "glbtq", + "lesbian", + "lgbt", + "lgbtq", + "lgbtqia", + "pride", + "queer", + "rainbow", + "trans", + "transgender" + ], + "unicode": "🏳️‍🌈" + }, + { + "group": 9, + "hexcode": "1F3F3-FE0F-200D-26A7-FE0F", + "label": "transgender flag", + "order": 4775, + "tags": ["blue", "flag", "light", "pink", "transgender", "white"], + "unicode": "🏳️‍⚧️" + }, + { + "group": 9, + "hexcode": "1F3F4-200D-2620-FE0F", + "label": "pirate flag", + "order": 4779, + "tags": ["flag", "jolly", "pirate", "plunder", "roger", "treasure"], + "unicode": "🏴‍☠️" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1E8", + "label": "flag: Ascension Island", + "order": 4781, + "tags": ["AC", "flag"], + "unicode": "🇦🇨" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1E9", + "label": "flag: Andorra", + "order": 4782, + "tags": ["AD", "flag"], + "unicode": "🇦🇩" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1EA", + "label": "flag: United Arab Emirates", + "order": 4783, + "tags": ["AE", "flag"], + "unicode": "🇦🇪" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1EB", + "label": "flag: Afghanistan", + "order": 4784, + "tags": ["AF", "flag"], + "unicode": "🇦🇫" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1EC", + "label": "flag: Antigua & Barbuda", + "order": 4785, + "tags": ["AG", "flag"], + "unicode": "🇦🇬" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1EE", + "label": "flag: Anguilla", + "order": 4786, + "tags": ["AI", "flag"], + "unicode": "🇦🇮" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1F1", + "label": "flag: Albania", + "order": 4787, + "tags": ["AL", "flag"], + "unicode": "🇦🇱" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1F2", + "label": "flag: Armenia", + "order": 4788, + "tags": ["AM", "flag"], + "unicode": "🇦🇲" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1F4", + "label": "flag: Angola", + "order": 4789, + "tags": ["AO", "flag"], + "unicode": "🇦🇴" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1F6", + "label": "flag: Antarctica", + "order": 4790, + "tags": ["AQ", "flag"], + "unicode": "🇦🇶" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1F7", + "label": "flag: Argentina", + "order": 4791, + "tags": ["AR", "flag"], + "unicode": "🇦🇷" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1F8", + "label": "flag: American Samoa", + "order": 4792, + "tags": ["AS", "flag"], + "unicode": "🇦🇸" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1F9", + "label": "flag: Austria", + "order": 4793, + "tags": ["AT", "flag"], + "unicode": "🇦🇹" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1FA", + "label": "flag: Australia", + "order": 4794, + "tags": ["AU", "flag"], + "unicode": "🇦🇺" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1FC", + "label": "flag: Aruba", + "order": 4795, + "tags": ["AW", "flag"], + "unicode": "🇦🇼" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1FD", + "label": "flag: Åland Islands", + "order": 4796, + "tags": ["AX", "flag"], + "unicode": "🇦🇽" + }, + { + "group": 9, + "hexcode": "1F1E6-1F1FF", + "label": "flag: Azerbaijan", + "order": 4797, + "tags": ["AZ", "flag"], + "unicode": "🇦🇿" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1E6", + "label": "flag: Bosnia & Herzegovina", + "order": 4798, + "tags": ["BA", "flag"], + "unicode": "🇧🇦" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1E7", + "label": "flag: Barbados", + "order": 4799, + "tags": ["BB", "flag"], + "unicode": "🇧🇧" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1E9", + "label": "flag: Bangladesh", + "order": 4800, + "tags": ["BD", "flag"], + "unicode": "🇧🇩" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1EA", + "label": "flag: Belgium", + "order": 4801, + "tags": ["BE", "flag"], + "unicode": "🇧🇪" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1EB", + "label": "flag: Burkina Faso", + "order": 4802, + "tags": ["BF", "flag"], + "unicode": "🇧🇫" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1EC", + "label": "flag: Bulgaria", + "order": 4803, + "tags": ["BG", "flag"], + "unicode": "🇧🇬" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1ED", + "label": "flag: Bahrain", + "order": 4804, + "tags": ["BH", "flag"], + "unicode": "🇧🇭" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1EE", + "label": "flag: Burundi", + "order": 4805, + "tags": ["BI", "flag"], + "unicode": "🇧🇮" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1EF", + "label": "flag: Benin", + "order": 4806, + "tags": ["BJ", "flag"], + "unicode": "🇧🇯" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1F1", + "label": "flag: St. Barthélemy", + "order": 4807, + "tags": ["BL", "flag"], + "unicode": "🇧🇱" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1F2", + "label": "flag: Bermuda", + "order": 4808, + "tags": ["BM", "flag"], + "unicode": "🇧🇲" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1F3", + "label": "flag: Brunei", + "order": 4809, + "tags": ["BN", "flag"], + "unicode": "🇧🇳" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1F4", + "label": "flag: Bolivia", + "order": 4810, + "tags": ["BO", "flag"], + "unicode": "🇧🇴" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1F6", + "label": "flag: Caribbean Netherlands", + "order": 4811, + "tags": ["BQ", "flag"], + "unicode": "🇧🇶" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1F7", + "label": "flag: Brazil", + "order": 4812, + "tags": ["BR", "flag"], + "unicode": "🇧🇷" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1F8", + "label": "flag: Bahamas", + "order": 4813, + "tags": ["BS", "flag"], + "unicode": "🇧🇸" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1F9", + "label": "flag: Bhutan", + "order": 4814, + "tags": ["BT", "flag"], + "unicode": "🇧🇹" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1FB", + "label": "flag: Bouvet Island", + "order": 4815, + "tags": ["BV", "flag"], + "unicode": "🇧🇻" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1FC", + "label": "flag: Botswana", + "order": 4816, + "tags": ["BW", "flag"], + "unicode": "🇧🇼" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1FE", + "label": "flag: Belarus", + "order": 4817, + "tags": ["BY", "flag"], + "unicode": "🇧🇾" + }, + { + "group": 9, + "hexcode": "1F1E7-1F1FF", + "label": "flag: Belize", + "order": 4818, + "tags": ["BZ", "flag"], + "unicode": "🇧🇿" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1E6", + "label": "flag: Canada", + "order": 4819, + "tags": ["CA", "flag"], + "unicode": "🇨🇦" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1E8", + "label": "flag: Cocos (Keeling) Islands", + "order": 4820, + "tags": ["CC", "flag"], + "unicode": "🇨🇨" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1E9", + "label": "flag: Congo - Kinshasa", + "order": 4821, + "tags": ["CD", "flag"], + "unicode": "🇨🇩" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1EB", + "label": "flag: Central African Republic", + "order": 4822, + "tags": ["CF", "flag"], + "unicode": "🇨🇫" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1EC", + "label": "flag: Congo - Brazzaville", + "order": 4823, + "tags": ["CG", "flag"], + "unicode": "🇨🇬" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1ED", + "label": "flag: Switzerland", + "order": 4824, + "tags": ["CH", "flag"], + "unicode": "🇨🇭" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1EE", + "label": "flag: Côte d’Ivoire", + "order": 4825, + "tags": ["CI", "flag"], + "unicode": "🇨🇮" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1F0", + "label": "flag: Cook Islands", + "order": 4826, + "tags": ["CK", "flag"], + "unicode": "🇨🇰" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1F1", + "label": "flag: Chile", + "order": 4827, + "tags": ["CL", "flag"], + "unicode": "🇨🇱" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1F2", + "label": "flag: Cameroon", + "order": 4828, + "tags": ["CM", "flag"], + "unicode": "🇨🇲" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1F3", + "label": "flag: China", + "order": 4829, + "tags": ["CN", "flag"], + "unicode": "🇨🇳" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1F4", + "label": "flag: Colombia", + "order": 4830, + "tags": ["CO", "flag"], + "unicode": "🇨🇴" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1F5", + "label": "flag: Clipperton Island", + "order": 4831, + "tags": ["CP", "flag"], + "unicode": "🇨🇵" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1F6", + "label": "flag: Sark", + "order": 4832, + "tags": ["CQ", "flag"], + "unicode": "🇨🇶" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1F7", + "label": "flag: Costa Rica", + "order": 4833, + "tags": ["CR", "flag"], + "unicode": "🇨🇷" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1FA", + "label": "flag: Cuba", + "order": 4834, + "tags": ["CU", "flag"], + "unicode": "🇨🇺" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1FB", + "label": "flag: Cape Verde", + "order": 4835, + "tags": ["CV", "flag"], + "unicode": "🇨🇻" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1FC", + "label": "flag: Curaçao", + "order": 4836, + "tags": ["CW", "flag"], + "unicode": "🇨🇼" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1FD", + "label": "flag: Christmas Island", + "order": 4837, + "tags": ["CX", "flag"], + "unicode": "🇨🇽" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1FE", + "label": "flag: Cyprus", + "order": 4838, + "tags": ["CY", "flag"], + "unicode": "🇨🇾" + }, + { + "group": 9, + "hexcode": "1F1E8-1F1FF", + "label": "flag: Czechia", + "order": 4839, + "tags": ["CZ", "flag"], + "unicode": "🇨🇿" + }, + { + "group": 9, + "hexcode": "1F1E9-1F1EA", + "label": "flag: Germany", + "order": 4840, + "tags": ["DE", "flag"], + "unicode": "🇩🇪" + }, + { + "group": 9, + "hexcode": "1F1E9-1F1EC", + "label": "flag: Diego Garcia", + "order": 4841, + "tags": ["DG", "flag"], + "unicode": "🇩🇬" + }, + { + "group": 9, + "hexcode": "1F1E9-1F1EF", + "label": "flag: Djibouti", + "order": 4842, + "tags": ["DJ", "flag"], + "unicode": "🇩🇯" + }, + { + "group": 9, + "hexcode": "1F1E9-1F1F0", + "label": "flag: Denmark", + "order": 4843, + "tags": ["DK", "flag"], + "unicode": "🇩🇰" + }, + { + "group": 9, + "hexcode": "1F1E9-1F1F2", + "label": "flag: Dominica", + "order": 4844, + "tags": ["DM", "flag"], + "unicode": "🇩🇲" + }, + { + "group": 9, + "hexcode": "1F1E9-1F1F4", + "label": "flag: Dominican Republic", + "order": 4845, + "tags": ["DO", "flag"], + "unicode": "🇩🇴" + }, + { + "group": 9, + "hexcode": "1F1E9-1F1FF", + "label": "flag: Algeria", + "order": 4846, + "tags": ["DZ", "flag"], + "unicode": "🇩🇿" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1E6", + "label": "flag: Ceuta & Melilla", + "order": 4847, + "tags": ["EA", "flag"], + "unicode": "🇪🇦" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1E8", + "label": "flag: Ecuador", + "order": 4848, + "tags": ["EC", "flag"], + "unicode": "🇪🇨" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1EA", + "label": "flag: Estonia", + "order": 4849, + "tags": ["EE", "flag"], + "unicode": "🇪🇪" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1EC", + "label": "flag: Egypt", + "order": 4850, + "tags": ["EG", "flag"], + "unicode": "🇪🇬" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1ED", + "label": "flag: Western Sahara", + "order": 4851, + "tags": ["EH", "flag"], + "unicode": "🇪🇭" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1F7", + "label": "flag: Eritrea", + "order": 4852, + "tags": ["ER", "flag"], + "unicode": "🇪🇷" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1F8", + "label": "flag: Spain", + "order": 4853, + "tags": ["ES", "flag"], + "unicode": "🇪🇸" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1F9", + "label": "flag: Ethiopia", + "order": 4854, + "tags": ["ET", "flag"], + "unicode": "🇪🇹" + }, + { + "group": 9, + "hexcode": "1F1EA-1F1FA", + "label": "flag: European Union", + "order": 4855, + "tags": ["EU", "flag"], + "unicode": "🇪🇺" + }, + { + "group": 9, + "hexcode": "1F1EB-1F1EE", + "label": "flag: Finland", + "order": 4856, + "tags": ["FI", "flag"], + "unicode": "🇫🇮" + }, + { + "group": 9, + "hexcode": "1F1EB-1F1EF", + "label": "flag: Fiji", + "order": 4857, + "tags": ["FJ", "flag"], + "unicode": "🇫🇯" + }, + { + "group": 9, + "hexcode": "1F1EB-1F1F0", + "label": "flag: Falkland Islands", + "order": 4858, + "tags": ["FK", "flag"], + "unicode": "🇫🇰" + }, + { + "group": 9, + "hexcode": "1F1EB-1F1F2", + "label": "flag: Micronesia", + "order": 4859, + "tags": ["FM", "flag"], + "unicode": "🇫🇲" + }, + { + "group": 9, + "hexcode": "1F1EB-1F1F4", + "label": "flag: Faroe Islands", + "order": 4860, + "tags": ["FO", "flag"], + "unicode": "🇫🇴" + }, + { + "group": 9, + "hexcode": "1F1EB-1F1F7", + "label": "flag: France", + "order": 4861, + "tags": ["FR", "flag"], + "unicode": "🇫🇷" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1E6", + "label": "flag: Gabon", + "order": 4862, + "tags": ["GA", "flag"], + "unicode": "🇬🇦" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1E7", + "label": "flag: United Kingdom", + "order": 4863, + "tags": ["GB", "flag"], + "unicode": "🇬🇧" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1E9", + "label": "flag: Grenada", + "order": 4864, + "tags": ["GD", "flag"], + "unicode": "🇬🇩" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1EA", + "label": "flag: Georgia", + "order": 4865, + "tags": ["GE", "flag"], + "unicode": "🇬🇪" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1EB", + "label": "flag: French Guiana", + "order": 4866, + "tags": ["GF", "flag"], + "unicode": "🇬🇫" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1EC", + "label": "flag: Guernsey", + "order": 4867, + "tags": ["GG", "flag"], + "unicode": "🇬🇬" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1ED", + "label": "flag: Ghana", + "order": 4868, + "tags": ["GH", "flag"], + "unicode": "🇬🇭" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1EE", + "label": "flag: Gibraltar", + "order": 4869, + "tags": ["GI", "flag"], + "unicode": "🇬🇮" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1F1", + "label": "flag: Greenland", + "order": 4870, + "tags": ["GL", "flag"], + "unicode": "🇬🇱" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1F2", + "label": "flag: Gambia", + "order": 4871, + "tags": ["GM", "flag"], + "unicode": "🇬🇲" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1F3", + "label": "flag: Guinea", + "order": 4872, + "tags": ["GN", "flag"], + "unicode": "🇬🇳" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1F5", + "label": "flag: Guadeloupe", + "order": 4873, + "tags": ["GP", "flag"], + "unicode": "🇬🇵" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1F6", + "label": "flag: Equatorial Guinea", + "order": 4874, + "tags": ["GQ", "flag"], + "unicode": "🇬🇶" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1F7", + "label": "flag: Greece", + "order": 4875, + "tags": ["GR", "flag"], + "unicode": "🇬🇷" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1F8", + "label": "flag: South Georgia & South Sandwich Islands", + "order": 4876, + "tags": ["GS", "flag"], + "unicode": "🇬🇸" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1F9", + "label": "flag: Guatemala", + "order": 4877, + "tags": ["GT", "flag"], + "unicode": "🇬🇹" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1FA", + "label": "flag: Guam", + "order": 4878, + "tags": ["GU", "flag"], + "unicode": "🇬🇺" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1FC", + "label": "flag: Guinea-Bissau", + "order": 4879, + "tags": ["GW", "flag"], + "unicode": "🇬🇼" + }, + { + "group": 9, + "hexcode": "1F1EC-1F1FE", + "label": "flag: Guyana", + "order": 4880, + "tags": ["GY", "flag"], + "unicode": "🇬🇾" + }, + { + "group": 9, + "hexcode": "1F1ED-1F1F0", + "label": "flag: Hong Kong SAR China", + "order": 4881, + "tags": ["HK", "flag"], + "unicode": "🇭🇰" + }, + { + "group": 9, + "hexcode": "1F1ED-1F1F2", + "label": "flag: Heard & McDonald Islands", + "order": 4882, + "tags": ["HM", "flag"], + "unicode": "🇭🇲" + }, + { + "group": 9, + "hexcode": "1F1ED-1F1F3", + "label": "flag: Honduras", + "order": 4883, + "tags": ["HN", "flag"], + "unicode": "🇭🇳" + }, + { + "group": 9, + "hexcode": "1F1ED-1F1F7", + "label": "flag: Croatia", + "order": 4884, + "tags": ["HR", "flag"], + "unicode": "🇭🇷" + }, + { + "group": 9, + "hexcode": "1F1ED-1F1F9", + "label": "flag: Haiti", + "order": 4885, + "tags": ["HT", "flag"], + "unicode": "🇭🇹" + }, + { + "group": 9, + "hexcode": "1F1ED-1F1FA", + "label": "flag: Hungary", + "order": 4886, + "tags": ["HU", "flag"], + "unicode": "🇭🇺" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1E8", + "label": "flag: Canary Islands", + "order": 4887, + "tags": ["IC", "flag"], + "unicode": "🇮🇨" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1E9", + "label": "flag: Indonesia", + "order": 4888, + "tags": ["ID", "flag"], + "unicode": "🇮🇩" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1EA", + "label": "flag: Ireland", + "order": 4889, + "tags": ["IE", "flag"], + "unicode": "🇮🇪" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1F1", + "label": "flag: Israel", + "order": 4890, + "tags": ["IL", "flag"], + "unicode": "🇮🇱" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1F2", + "label": "flag: Isle of Man", + "order": 4891, + "tags": ["IM", "flag"], + "unicode": "🇮🇲" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1F3", + "label": "flag: India", + "order": 4892, + "tags": ["IN", "flag"], + "unicode": "🇮🇳" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1F4", + "label": "flag: British Indian Ocean Territory", + "order": 4893, + "tags": ["IO", "flag"], + "unicode": "🇮🇴" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1F6", + "label": "flag: Iraq", + "order": 4894, + "tags": ["IQ", "flag"], + "unicode": "🇮🇶" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1F7", + "label": "flag: Iran", + "order": 4895, + "tags": ["IR", "flag"], + "unicode": "🇮🇷" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1F8", + "label": "flag: Iceland", + "order": 4896, + "tags": ["IS", "flag"], + "unicode": "🇮🇸" + }, + { + "group": 9, + "hexcode": "1F1EE-1F1F9", + "label": "flag: Italy", + "order": 4897, + "tags": ["IT", "flag"], + "unicode": "🇮🇹" + }, + { + "group": 9, + "hexcode": "1F1EF-1F1EA", + "label": "flag: Jersey", + "order": 4898, + "tags": ["JE", "flag"], + "unicode": "🇯🇪" + }, + { + "group": 9, + "hexcode": "1F1EF-1F1F2", + "label": "flag: Jamaica", + "order": 4899, + "tags": ["JM", "flag"], + "unicode": "🇯🇲" + }, + { + "group": 9, + "hexcode": "1F1EF-1F1F4", + "label": "flag: Jordan", + "order": 4900, + "tags": ["JO", "flag"], + "unicode": "🇯🇴" + }, + { + "group": 9, + "hexcode": "1F1EF-1F1F5", + "label": "flag: Japan", + "order": 4901, + "tags": ["JP", "flag"], + "unicode": "🇯🇵" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1EA", + "label": "flag: Kenya", + "order": 4902, + "tags": ["KE", "flag"], + "unicode": "🇰🇪" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1EC", + "label": "flag: Kyrgyzstan", + "order": 4903, + "tags": ["KG", "flag"], + "unicode": "🇰🇬" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1ED", + "label": "flag: Cambodia", + "order": 4904, + "tags": ["KH", "flag"], + "unicode": "🇰🇭" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1EE", + "label": "flag: Kiribati", + "order": 4905, + "tags": ["KI", "flag"], + "unicode": "🇰🇮" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1F2", + "label": "flag: Comoros", + "order": 4906, + "tags": ["KM", "flag"], + "unicode": "🇰🇲" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1F3", + "label": "flag: St. Kitts & Nevis", + "order": 4907, + "tags": ["KN", "flag"], + "unicode": "🇰🇳" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1F5", + "label": "flag: North Korea", + "order": 4908, + "tags": ["KP", "flag"], + "unicode": "🇰🇵" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1F7", + "label": "flag: South Korea", + "order": 4909, + "tags": ["KR", "flag"], + "unicode": "🇰🇷" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1FC", + "label": "flag: Kuwait", + "order": 4910, + "tags": ["KW", "flag"], + "unicode": "🇰🇼" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1FE", + "label": "flag: Cayman Islands", + "order": 4911, + "tags": ["KY", "flag"], + "unicode": "🇰🇾" + }, + { + "group": 9, + "hexcode": "1F1F0-1F1FF", + "label": "flag: Kazakhstan", + "order": 4912, + "tags": ["KZ", "flag"], + "unicode": "🇰🇿" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1E6", + "label": "flag: Laos", + "order": 4913, + "tags": ["LA", "flag"], + "unicode": "🇱🇦" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1E7", + "label": "flag: Lebanon", + "order": 4914, + "tags": ["LB", "flag"], + "unicode": "🇱🇧" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1E8", + "label": "flag: St. Lucia", + "order": 4915, + "tags": ["LC", "flag"], + "unicode": "🇱🇨" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1EE", + "label": "flag: Liechtenstein", + "order": 4916, + "tags": ["LI", "flag"], + "unicode": "🇱🇮" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1F0", + "label": "flag: Sri Lanka", + "order": 4917, + "tags": ["LK", "flag"], + "unicode": "🇱🇰" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1F7", + "label": "flag: Liberia", + "order": 4918, + "tags": ["LR", "flag"], + "unicode": "🇱🇷" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1F8", + "label": "flag: Lesotho", + "order": 4919, + "tags": ["LS", "flag"], + "unicode": "🇱🇸" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1F9", + "label": "flag: Lithuania", + "order": 4920, + "tags": ["LT", "flag"], + "unicode": "🇱🇹" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1FA", + "label": "flag: Luxembourg", + "order": 4921, + "tags": ["LU", "flag"], + "unicode": "🇱🇺" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1FB", + "label": "flag: Latvia", + "order": 4922, + "tags": ["LV", "flag"], + "unicode": "🇱🇻" + }, + { + "group": 9, + "hexcode": "1F1F1-1F1FE", + "label": "flag: Libya", + "order": 4923, + "tags": ["LY", "flag"], + "unicode": "🇱🇾" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1E6", + "label": "flag: Morocco", + "order": 4924, + "tags": ["MA", "flag"], + "unicode": "🇲🇦" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1E8", + "label": "flag: Monaco", + "order": 4925, + "tags": ["MC", "flag"], + "unicode": "🇲🇨" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1E9", + "label": "flag: Moldova", + "order": 4926, + "tags": ["MD", "flag"], + "unicode": "🇲🇩" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1EA", + "label": "flag: Montenegro", + "order": 4927, + "tags": ["ME", "flag"], + "unicode": "🇲🇪" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1EB", + "label": "flag: St. Martin", + "order": 4928, + "tags": ["MF", "flag"], + "unicode": "🇲🇫" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1EC", + "label": "flag: Madagascar", + "order": 4929, + "tags": ["MG", "flag"], + "unicode": "🇲🇬" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1ED", + "label": "flag: Marshall Islands", + "order": 4930, + "tags": ["MH", "flag"], + "unicode": "🇲🇭" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F0", + "label": "flag: North Macedonia", + "order": 4931, + "tags": ["MK", "flag"], + "unicode": "🇲🇰" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F1", + "label": "flag: Mali", + "order": 4932, + "tags": ["ML", "flag"], + "unicode": "🇲🇱" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F2", + "label": "flag: Myanmar (Burma)", + "order": 4933, + "tags": ["MM", "flag"], + "unicode": "🇲🇲" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F3", + "label": "flag: Mongolia", + "order": 4934, + "tags": ["MN", "flag"], + "unicode": "🇲🇳" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F4", + "label": "flag: Macao SAR China", + "order": 4935, + "tags": ["MO", "flag"], + "unicode": "🇲🇴" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F5", + "label": "flag: Northern Mariana Islands", + "order": 4936, + "tags": ["MP", "flag"], + "unicode": "🇲🇵" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F6", + "label": "flag: Martinique", + "order": 4937, + "tags": ["MQ", "flag"], + "unicode": "🇲🇶" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F7", + "label": "flag: Mauritania", + "order": 4938, + "tags": ["MR", "flag"], + "unicode": "🇲🇷" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F8", + "label": "flag: Montserrat", + "order": 4939, + "tags": ["MS", "flag"], + "unicode": "🇲🇸" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1F9", + "label": "flag: Malta", + "order": 4940, + "tags": ["MT", "flag"], + "unicode": "🇲🇹" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1FA", + "label": "flag: Mauritius", + "order": 4941, + "tags": ["MU", "flag"], + "unicode": "🇲🇺" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1FB", + "label": "flag: Maldives", + "order": 4942, + "tags": ["MV", "flag"], + "unicode": "🇲🇻" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1FC", + "label": "flag: Malawi", + "order": 4943, + "tags": ["MW", "flag"], + "unicode": "🇲🇼" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1FD", + "label": "flag: Mexico", + "order": 4944, + "tags": ["MX", "flag"], + "unicode": "🇲🇽" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1FE", + "label": "flag: Malaysia", + "order": 4945, + "tags": ["MY", "flag"], + "unicode": "🇲🇾" + }, + { + "group": 9, + "hexcode": "1F1F2-1F1FF", + "label": "flag: Mozambique", + "order": 4946, + "tags": ["MZ", "flag"], + "unicode": "🇲🇿" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1E6", + "label": "flag: Namibia", + "order": 4947, + "tags": ["NA", "flag"], + "unicode": "🇳🇦" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1E8", + "label": "flag: New Caledonia", + "order": 4948, + "tags": ["NC", "flag"], + "unicode": "🇳🇨" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1EA", + "label": "flag: Niger", + "order": 4949, + "tags": ["NE", "flag"], + "unicode": "🇳🇪" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1EB", + "label": "flag: Norfolk Island", + "order": 4950, + "tags": ["NF", "flag"], + "unicode": "🇳🇫" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1EC", + "label": "flag: Nigeria", + "order": 4951, + "tags": ["NG", "flag"], + "unicode": "🇳🇬" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1EE", + "label": "flag: Nicaragua", + "order": 4952, + "tags": ["NI", "flag"], + "unicode": "🇳🇮" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1F1", + "label": "flag: Netherlands", + "order": 4953, + "tags": ["NL", "flag"], + "unicode": "🇳🇱" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1F4", + "label": "flag: Norway", + "order": 4954, + "tags": ["NO", "flag"], + "unicode": "🇳🇴" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1F5", + "label": "flag: Nepal", + "order": 4955, + "tags": ["NP", "flag"], + "unicode": "🇳🇵" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1F7", + "label": "flag: Nauru", + "order": 4956, + "tags": ["NR", "flag"], + "unicode": "🇳🇷" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1FA", + "label": "flag: Niue", + "order": 4957, + "tags": ["NU", "flag"], + "unicode": "🇳🇺" + }, + { + "group": 9, + "hexcode": "1F1F3-1F1FF", + "label": "flag: New Zealand", + "order": 4958, + "tags": ["NZ", "flag"], + "unicode": "🇳🇿" + }, + { + "group": 9, + "hexcode": "1F1F4-1F1F2", + "label": "flag: Oman", + "order": 4959, + "tags": ["OM", "flag"], + "unicode": "🇴🇲" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1E6", + "label": "flag: Panama", + "order": 4960, + "tags": ["PA", "flag"], + "unicode": "🇵🇦" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1EA", + "label": "flag: Peru", + "order": 4961, + "tags": ["PE", "flag"], + "unicode": "🇵🇪" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1EB", + "label": "flag: French Polynesia", + "order": 4962, + "tags": ["PF", "flag"], + "unicode": "🇵🇫" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1EC", + "label": "flag: Papua New Guinea", + "order": 4963, + "tags": ["PG", "flag"], + "unicode": "🇵🇬" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1ED", + "label": "flag: Philippines", + "order": 4964, + "tags": ["PH", "flag"], + "unicode": "🇵🇭" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1F0", + "label": "flag: Pakistan", + "order": 4965, + "tags": ["PK", "flag"], + "unicode": "🇵🇰" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1F1", + "label": "flag: Poland", + "order": 4966, + "tags": ["PL", "flag"], + "unicode": "🇵🇱" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1F2", + "label": "flag: St. Pierre & Miquelon", + "order": 4967, + "tags": ["PM", "flag"], + "unicode": "🇵🇲" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1F3", + "label": "flag: Pitcairn Islands", + "order": 4968, + "tags": ["PN", "flag"], + "unicode": "🇵🇳" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1F7", + "label": "flag: Puerto Rico", + "order": 4969, + "tags": ["PR", "flag"], + "unicode": "🇵🇷" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1F8", + "label": "flag: Palestinian Territories", + "order": 4970, + "tags": ["PS", "flag"], + "unicode": "🇵🇸" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1F9", + "label": "flag: Portugal", + "order": 4971, + "tags": ["PT", "flag"], + "unicode": "🇵🇹" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1FC", + "label": "flag: Palau", + "order": 4972, + "tags": ["PW", "flag"], + "unicode": "🇵🇼" + }, + { + "group": 9, + "hexcode": "1F1F5-1F1FE", + "label": "flag: Paraguay", + "order": 4973, + "tags": ["PY", "flag"], + "unicode": "🇵🇾" + }, + { + "group": 9, + "hexcode": "1F1F6-1F1E6", + "label": "flag: Qatar", + "order": 4974, + "tags": ["QA", "flag"], + "unicode": "🇶🇦" + }, + { + "group": 9, + "hexcode": "1F1F7-1F1EA", + "label": "flag: Réunion", + "order": 4975, + "tags": ["RE", "flag"], + "unicode": "🇷🇪" + }, + { + "group": 9, + "hexcode": "1F1F7-1F1F4", + "label": "flag: Romania", + "order": 4976, + "tags": ["RO", "flag"], + "unicode": "🇷🇴" + }, + { + "group": 9, + "hexcode": "1F1F7-1F1F8", + "label": "flag: Serbia", + "order": 4977, + "tags": ["RS", "flag"], + "unicode": "🇷🇸" + }, + { + "group": 9, + "hexcode": "1F1F7-1F1FA", + "label": "flag: Russia", + "order": 4978, + "tags": ["RU", "flag"], + "unicode": "🇷🇺" + }, + { + "group": 9, + "hexcode": "1F1F7-1F1FC", + "label": "flag: Rwanda", + "order": 4979, + "tags": ["RW", "flag"], + "unicode": "🇷🇼" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1E6", + "label": "flag: Saudi Arabia", + "order": 4980, + "tags": ["SA", "flag"], + "unicode": "🇸🇦" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1E7", + "label": "flag: Solomon Islands", + "order": 4981, + "tags": ["SB", "flag"], + "unicode": "🇸🇧" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1E8", + "label": "flag: Seychelles", + "order": 4982, + "tags": ["SC", "flag"], + "unicode": "🇸🇨" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1E9", + "label": "flag: Sudan", + "order": 4983, + "tags": ["SD", "flag"], + "unicode": "🇸🇩" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1EA", + "label": "flag: Sweden", + "order": 4984, + "tags": ["SE", "flag"], + "unicode": "🇸🇪" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1EC", + "label": "flag: Singapore", + "order": 4985, + "tags": ["SG", "flag"], + "unicode": "🇸🇬" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1ED", + "label": "flag: St. Helena", + "order": 4986, + "tags": ["SH", "flag"], + "unicode": "🇸🇭" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1EE", + "label": "flag: Slovenia", + "order": 4987, + "tags": ["SI", "flag"], + "unicode": "🇸🇮" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1EF", + "label": "flag: Svalbard & Jan Mayen", + "order": 4988, + "tags": ["SJ", "flag"], + "unicode": "🇸🇯" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1F0", + "label": "flag: Slovakia", + "order": 4989, + "tags": ["SK", "flag"], + "unicode": "🇸🇰" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1F1", + "label": "flag: Sierra Leone", + "order": 4990, + "tags": ["SL", "flag"], + "unicode": "🇸🇱" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1F2", + "label": "flag: San Marino", + "order": 4991, + "tags": ["SM", "flag"], + "unicode": "🇸🇲" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1F3", + "label": "flag: Senegal", + "order": 4992, + "tags": ["SN", "flag"], + "unicode": "🇸🇳" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1F4", + "label": "flag: Somalia", + "order": 4993, + "tags": ["SO", "flag"], + "unicode": "🇸🇴" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1F7", + "label": "flag: Suriname", + "order": 4994, + "tags": ["SR", "flag"], + "unicode": "🇸🇷" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1F8", + "label": "flag: South Sudan", + "order": 4995, + "tags": ["SS", "flag"], + "unicode": "🇸🇸" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1F9", + "label": "flag: São Tomé & Príncipe", + "order": 4996, + "tags": ["ST", "flag"], + "unicode": "🇸🇹" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1FB", + "label": "flag: El Salvador", + "order": 4997, + "tags": ["SV", "flag"], + "unicode": "🇸🇻" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1FD", + "label": "flag: Sint Maarten", + "order": 4998, + "tags": ["SX", "flag"], + "unicode": "🇸🇽" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1FE", + "label": "flag: Syria", + "order": 4999, + "tags": ["SY", "flag"], + "unicode": "🇸🇾" + }, + { + "group": 9, + "hexcode": "1F1F8-1F1FF", + "label": "flag: Eswatini", + "order": 5000, + "tags": ["SZ", "flag"], + "unicode": "🇸🇿" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1E6", + "label": "flag: Tristan da Cunha", + "order": 5001, + "tags": ["TA", "flag"], + "unicode": "🇹🇦" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1E8", + "label": "flag: Turks & Caicos Islands", + "order": 5002, + "tags": ["TC", "flag"], + "unicode": "🇹🇨" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1E9", + "label": "flag: Chad", + "order": 5003, + "tags": ["TD", "flag"], + "unicode": "🇹🇩" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1EB", + "label": "flag: French Southern Territories", + "order": 5004, + "tags": ["TF", "flag"], + "unicode": "🇹🇫" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1EC", + "label": "flag: Togo", + "order": 5005, + "tags": ["TG", "flag"], + "unicode": "🇹🇬" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1ED", + "label": "flag: Thailand", + "order": 5006, + "tags": ["TH", "flag"], + "unicode": "🇹🇭" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1EF", + "label": "flag: Tajikistan", + "order": 5007, + "tags": ["TJ", "flag"], + "unicode": "🇹🇯" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1F0", + "label": "flag: Tokelau", + "order": 5008, + "tags": ["TK", "flag"], + "unicode": "🇹🇰" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1F1", + "label": "flag: Timor-Leste", + "order": 5009, + "tags": ["TL", "flag"], + "unicode": "🇹🇱" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1F2", + "label": "flag: Turkmenistan", + "order": 5010, + "tags": ["TM", "flag"], + "unicode": "🇹🇲" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1F3", + "label": "flag: Tunisia", + "order": 5011, + "tags": ["TN", "flag"], + "unicode": "🇹🇳" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1F4", + "label": "flag: Tonga", + "order": 5012, + "tags": ["TO", "flag"], + "unicode": "🇹🇴" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1F7", + "label": "flag: Türkiye", + "order": 5013, + "tags": ["TR", "flag"], + "unicode": "🇹🇷" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1F9", + "label": "flag: Trinidad & Tobago", + "order": 5014, + "tags": ["TT", "flag"], + "unicode": "🇹🇹" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1FB", + "label": "flag: Tuvalu", + "order": 5015, + "tags": ["TV", "flag"], + "unicode": "🇹🇻" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1FC", + "label": "flag: Taiwan", + "order": 5016, + "tags": ["TW", "flag"], + "unicode": "🇹🇼" + }, + { + "group": 9, + "hexcode": "1F1F9-1F1FF", + "label": "flag: Tanzania", + "order": 5017, + "tags": ["TZ", "flag"], + "unicode": "🇹🇿" + }, + { + "group": 9, + "hexcode": "1F1FA-1F1E6", + "label": "flag: Ukraine", + "order": 5018, + "tags": ["UA", "flag"], + "unicode": "🇺🇦" + }, + { + "group": 9, + "hexcode": "1F1FA-1F1EC", + "label": "flag: Uganda", + "order": 5019, + "tags": ["UG", "flag"], + "unicode": "🇺🇬" + }, + { + "group": 9, + "hexcode": "1F1FA-1F1F2", + "label": "flag: U.S. Outlying Islands", + "order": 5020, + "tags": ["UM", "flag"], + "unicode": "🇺🇲" + }, + { + "group": 9, + "hexcode": "1F1FA-1F1F3", + "label": "flag: United Nations", + "order": 5021, + "tags": ["UN", "flag"], + "unicode": "🇺🇳" + }, + { + "group": 9, + "hexcode": "1F1FA-1F1F8", + "label": "flag: United States", + "order": 5022, + "tags": ["US", "flag"], + "unicode": "🇺🇸" + }, + { + "group": 9, + "hexcode": "1F1FA-1F1FE", + "label": "flag: Uruguay", + "order": 5023, + "tags": ["UY", "flag"], + "unicode": "🇺🇾" + }, + { + "group": 9, + "hexcode": "1F1FA-1F1FF", + "label": "flag: Uzbekistan", + "order": 5024, + "tags": ["UZ", "flag"], + "unicode": "🇺🇿" + }, + { + "group": 9, + "hexcode": "1F1FB-1F1E6", + "label": "flag: Vatican City", + "order": 5025, + "tags": ["VA", "flag"], + "unicode": "🇻🇦" + }, + { + "group": 9, + "hexcode": "1F1FB-1F1E8", + "label": "flag: St. Vincent & Grenadines", + "order": 5026, + "tags": ["VC", "flag"], + "unicode": "🇻🇨" + }, + { + "group": 9, + "hexcode": "1F1FB-1F1EA", + "label": "flag: Venezuela", + "order": 5027, + "tags": ["VE", "flag"], + "unicode": "🇻🇪" + }, + { + "group": 9, + "hexcode": "1F1FB-1F1EC", + "label": "flag: British Virgin Islands", + "order": 5028, + "tags": ["VG", "flag"], + "unicode": "🇻🇬" + }, + { + "group": 9, + "hexcode": "1F1FB-1F1EE", + "label": "flag: U.S. Virgin Islands", + "order": 5029, + "tags": ["VI", "flag"], + "unicode": "🇻🇮" + }, + { + "group": 9, + "hexcode": "1F1FB-1F1F3", + "label": "flag: Vietnam", + "order": 5030, + "tags": ["VN", "flag"], + "unicode": "🇻🇳" + }, + { + "group": 9, + "hexcode": "1F1FB-1F1FA", + "label": "flag: Vanuatu", + "order": 5031, + "tags": ["VU", "flag"], + "unicode": "🇻🇺" + }, + { + "group": 9, + "hexcode": "1F1FC-1F1EB", + "label": "flag: Wallis & Futuna", + "order": 5032, + "tags": ["WF", "flag"], + "unicode": "🇼🇫" + }, + { + "group": 9, + "hexcode": "1F1FC-1F1F8", + "label": "flag: Samoa", + "order": 5033, + "tags": ["WS", "flag"], + "unicode": "🇼🇸" + }, + { + "group": 9, + "hexcode": "1F1FD-1F1F0", + "label": "flag: Kosovo", + "order": 5034, + "tags": ["XK", "flag"], + "unicode": "🇽🇰" + }, + { + "group": 9, + "hexcode": "1F1FE-1F1EA", + "label": "flag: Yemen", + "order": 5035, + "tags": ["YE", "flag"], + "unicode": "🇾🇪" + }, + { + "group": 9, + "hexcode": "1F1FE-1F1F9", + "label": "flag: Mayotte", + "order": 5036, + "tags": ["YT", "flag"], + "unicode": "🇾🇹" + }, + { + "group": 9, + "hexcode": "1F1FF-1F1E6", + "label": "flag: South Africa", + "order": 5037, + "tags": ["ZA", "flag"], + "unicode": "🇿🇦" + }, + { + "group": 9, + "hexcode": "1F1FF-1F1F2", + "label": "flag: Zambia", + "order": 5038, + "tags": ["ZM", "flag"], + "unicode": "🇿🇲" + }, + { + "group": 9, + "hexcode": "1F1FF-1F1FC", + "label": "flag: Zimbabwe", + "order": 5039, + "tags": ["ZW", "flag"], + "unicode": "🇿🇼" + }, + { + "group": 9, + "hexcode": "1F3F4-E0067-E0062-E0065-E006E-E0067-E007F", + "label": "flag: England", + "order": 5040, + "tags": ["flag", "gbeng"], + "unicode": "🏴󠁧󠁢󠁥󠁮󠁧󠁿" + }, + { + "group": 9, + "hexcode": "1F3F4-E0067-E0062-E0073-E0063-E0074-E007F", + "label": "flag: Scotland", + "order": 5041, + "tags": ["flag", "gbsct"], + "unicode": "🏴󠁧󠁢󠁳󠁣󠁴󠁿" + }, + { + "group": 9, + "hexcode": "1F3F4-E0067-E0062-E0077-E006C-E0073-E007F", + "label": "flag: Wales", + "order": 5042, + "tags": ["flag", "gbwls"], + "unicode": "🏴󠁧󠁢󠁷󠁬󠁳󠁿" + } + ] + } +] diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/emoji-picker.css.ts b/packages/frontend/component/src/ui/icon-picker/picker/emoji/emoji-picker.css.ts new file mode 100644 index 0000000000..e560f99e59 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/emoji-picker.css.ts @@ -0,0 +1,42 @@ +import { cssVarV2 } from '@toeverything/theme/v2'; +import { style } from '@vanilla-extract/css'; + +export const skinTrigger = style({}); + +// header skin +export const skinList = style({ + display: 'flex', + flexDirection: 'row', + gap: 2, +}); +export const skinItem = style({}); + +// content +export const loadingWrapper = style({ + height: 120, + flexGrow: 1, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + fontSize: 12, + color: cssVarV2.text.secondary, +}); + +export const footer = style({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '8px 16px', + borderTop: `0.5px solid ${cssVarV2.layer.insideBorder.border}`, +}); + +export const footerButton = style({}); +export const footerButtonActive = style({ + backgroundColor: cssVarV2.layer.background.hoverOverlay, +}); +export const footerIcon = style({ + color: cssVarV2.icon.secondary, +}); +export const footerIconActive = style({ + color: cssVarV2.icon.primary, +}); diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/emoji-picker.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/emoji-picker.tsx new file mode 100644 index 0000000000..ace2ffddbf --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/emoji-picker.tsx @@ -0,0 +1,332 @@ +import { RecentIcon, SearchIcon } from '@blocksuite/icons/rc'; +import { cssVarV2 } from '@toeverything/theme/v2'; +import clsx from 'clsx'; +import { + memo, + startTransition, + useCallback, + useEffect, + useRef, + useState, +} from 'react'; + +import { IconButton } from '../../../button'; +import Input from '../../../input'; +import { Loading } from '../../../loading'; +import { Menu } from '../../../menu'; +import { Scrollable } from '../../../scrollbar'; +import * as pickerStyles from '../picker.css'; +import { GROUP_ICON_MAP, type GroupName, GROUPS } from './constants'; +import rawData from './data/en.json'; +// import { emojiGroupList } from './gen-data'; +import * as styles from './emoji-picker.css'; +import type { CompactEmoji } from './type'; + +type EmojiGroup = { + name: string; + emojis: Array; +}; +const emojiGroupList = rawData as EmojiGroup[]; + +const useRecentEmojis = () => { + const [recentEmojis, setRecentEmojis] = useState>([]); + + useEffect(() => { + const recentEmojis = localStorage.getItem('recentEmojis'); + setRecentEmojis(recentEmojis ? recentEmojis.split(',') : []); + }, []); + + const add = useCallback((emoji: string) => { + setRecentEmojis(prevRecentEmojis => { + const newRecentEmojis = [ + emoji, + ...prevRecentEmojis.filter(e => e !== emoji), + ].slice(0, 10); + localStorage.setItem('recentEmojis', newRecentEmojis.join(',')); + return newRecentEmojis; + }); + }, []); + + return { + recentEmojis, + add, + }; +}; + +// Memoized individual emoji button to prevent unnecessary re-renders +const EmojiButton = memo(function EmojiButton({ + emoji, + onSelect, +}: { + emoji: string; + onSelect: (emoji: string) => void; +}) { + const handleClick = useCallback(() => { + onSelect(emoji); + }, [emoji, onSelect]); + + return ( + {emoji}} + onClick={handleClick} + /> + ); +}); + +// Memoized emoji groups to prevent unnecessary re-renders +const EmojiGroups = memo(function EmojiGroups({ + onSelect, + keyword, + skin, +}: { + onSelect: (emoji: string) => void; + keyword?: string; + skin?: number; +}) { + const [groups, setGroups] = useState([]); + + const loading = !keyword && !groups.length; + + useEffect(() => { + startTransition(() => { + if (!keyword) { + setGroups(emojiGroupList); + return; + } + + setGroups( + emojiGroupList + .map(group => ({ + ...group, + emojis: group.emojis.filter(emoji => + emoji.tags?.some(tag => tag.includes(keyword.toLowerCase())) + ), + })) + .filter(group => group.emojis.length > 0) + ); + }); + }, [keyword]); + + if (loading) { + return ( +
+ + Loading emojis... +
+ ); + } + + return groups.map(group => ( +
+
+ {group.name} +
+
+ {group.emojis.map(emoji => ( + + ))} +
+
+ )); +}); + +const skinList = [ + { unicode: '👋', value: undefined }, + { unicode: '👋🏻', value: 0 }, + { unicode: '👋🏼', value: 1 }, + { unicode: '👋🏽', value: 2 }, + { unicode: '👋🏾', value: 3 }, + { unicode: '👋🏿', value: 4 }, +]; + +export const EmojiPicker = ({ + onSelect, +}: { + onSelect?: (emoji: string) => void; +}) => { + const scrollableRef = useRef(null); + + const [keyword, setKeyword] = useState(''); + const [activeGroupId, setActiveGroupId] = useState( + undefined + ); + const [skin, setSkin] = useState(undefined); + const { recentEmojis, add: addRecent } = useRecentEmojis(); + + const checkActiveGroup = useCallback(() => { + const scrollable = scrollableRef.current; + if (!scrollable) return; + + // get actual scrollable element + const viewport = scrollable.querySelector( + '[data-radix-scroll-area-viewport]' + ) as HTMLElement; + if (!viewport) return; + + const scrollTop = viewport.scrollTop; + + // find the first group that is at the top of the scrollable element + for (let i = emojiGroupList.length - 1; i >= 0; i--) { + const group = emojiGroupList[i]; + const groupElement = viewport.querySelector( + `[data-group-name="${group.name}"]` + ) as HTMLElement; + if (!groupElement) continue; + + // use offsetTop to get the position of the element relative to the scrollable element + const elementTop = groupElement.offsetTop; + + if (elementTop <= scrollTop + 50) { + setActiveGroupId(group.name); + return; + } + } + }, []); + + const jumpToGroup = useCallback((groupName: string) => { + const groupElement = scrollableRef.current?.querySelector( + `[data-group-name="${groupName}"]` + ) as HTMLElement; + if (!groupElement) return; + + setActiveGroupId(groupName); + groupElement.scrollIntoView({ behavior: 'smooth' }); + }, []); + + const handleEmojiSelect = useCallback( + (emoji: string) => { + addRecent(emoji); + onSelect?.(emoji); + }, + [addRecent, onSelect] + ); + + useEffect(() => { + checkActiveGroup(); + }, [checkActiveGroup]); + + return ( +
+
+ + +
+ } + placeholder="Filter..." + /> + + {skinList.map(skin => ( + {skin.unicode}} + onClick={() => setSkin(skin.value)} + /> + ))} + + } + > + + {skin !== undefined + ? skinList[skin + 1].unicode + : skinList[0].unicode} + + } + /> + + + + + {/* Recent */} + {recentEmojis.length ? ( +
+
+ Recent +
+
+ {recentEmojis.map(emoji => ( + + ))} +
+
+ ) : null} + + {/* Groups */} + +
+ +
+
+ {['Recent', ...GROUPS].map(group => { + const Icon = GROUP_ICON_MAP[group as GroupName] ?? RecentIcon; + const active = activeGroupId === group; + return ( + + } + className={clsx( + active ? styles.footerButtonActive : styles.footerButton + )} + onClick={() => jumpToGroup(group)} + /> + ); + })} +
+ + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/gen-data.ts b/packages/frontend/component/src/ui/icon-picker/picker/emoji/gen-data.ts new file mode 100644 index 0000000000..0f84989a0c --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/gen-data.ts @@ -0,0 +1,59 @@ +import compactEmojis from 'emojibase-data/en/compact.json'; + +import { type GroupName, GROUPS } from './constants'; +import type { CompactEmoji } from './type'; + +const emojiGroupObj = GROUPS.reduce( + (acc, name) => ({ + ...acc, + [name]: { + emojis: [] as CompactEmoji[], + }, + }), + {} as Record +); +compactEmojis.forEach((emoji: CompactEmoji) => { + const group = emoji.group; + if (group === undefined) return; + + switch (group) { + case 0: + case 1: + emojiGroupObj['Smileys & People'].emojis.push(emoji); + break; + case 2: + // 🏻🏼🏽🏾🏿🦰🦱🦳🦲 + break; + case 3: + emojiGroupObj['Animals & Nature'].emojis.push(emoji); + break; + case 4: + emojiGroupObj['Food & Drink'].emojis.push(emoji); + break; + case 5: + emojiGroupObj['Travel & Places'].emojis.push(emoji); + break; + case 6: + emojiGroupObj['Activity'].emojis.push(emoji); + break; + case 7: + emojiGroupObj['Objects'].emojis.push(emoji); + break; + case 8: + emojiGroupObj['Symbols'].emojis.push(emoji); + break; + case 9: + emojiGroupObj['Flags'].emojis.push(emoji); + break; + } +}); + +export const emojiGroupList = GROUPS.map(name => ({ + name, + emojis: emojiGroupObj[name].emojis.sort((a, b) => a.order - b.order), +})); + +// it may take 300~500ms to group and sort the emojis in runtime +// so for now we just generate the data in build time +// and save it to ./data +console.log(JSON.stringify(emojiGroupList)); diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/activity.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/activity.tsx new file mode 100644 index 0000000000..23d6797c21 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/activity.tsx @@ -0,0 +1,21 @@ +import type { SVGProps } from 'react'; + +export const ActivityIcon = (attrs: SVGProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/animal.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/animal.tsx new file mode 100644 index 0000000000..ae637af839 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/animal.tsx @@ -0,0 +1,21 @@ +import type { SVGProps } from 'react'; + +export const AnimalIcon = ({ ...attrs }: SVGProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/flag.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/flag.tsx new file mode 100644 index 0000000000..3c1e28049b --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/flag.tsx @@ -0,0 +1,21 @@ +import type { SVGProps } from 'react'; + +export const FlagIcon = (attrs: SVGProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/food.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/food.tsx new file mode 100644 index 0000000000..84cadfceb4 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/food.tsx @@ -0,0 +1,21 @@ +import type { SVGProps } from 'react'; + +export const FoodIcon = ({ ...attrs }: SVGProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/object.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/object.tsx new file mode 100644 index 0000000000..291e4be119 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/object.tsx @@ -0,0 +1,21 @@ +import type { HTMLAttributes } from 'react'; + +export const ObjectIcon = (attrs: HTMLAttributes) => { + return ( + + + + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/smile.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/smile.tsx new file mode 100644 index 0000000000..8fdab11e9d --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/smile.tsx @@ -0,0 +1,21 @@ +import type { SVGProps } from 'react'; + +export const SmileIcon = ({ ...attrs }: SVGProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/symbol.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/symbol.tsx new file mode 100644 index 0000000000..9a89f8ceb4 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/symbol.tsx @@ -0,0 +1,21 @@ +import type { HTMLAttributes } from 'react'; + +export const SymbolIcon = (attrs: HTMLAttributes) => { + return ( + + + + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/travel.tsx b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/travel.tsx new file mode 100644 index 0000000000..19b167c039 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/icons/travel.tsx @@ -0,0 +1,21 @@ +import type { SVGProps } from 'react'; + +export const TravelIcon = (attrs: SVGProps) => { + return ( + + + + ); +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/emoji/type.ts b/packages/frontend/component/src/ui/icon-picker/picker/emoji/type.ts new file mode 100644 index 0000000000..8668aa3ac4 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/emoji/type.ts @@ -0,0 +1,11 @@ +export type CompactEmoji = { + label: string; + annotation?: string; + group: number; + hexcode: string; + order: number; + shortcodes: string[]; + tags: string[]; + unicode: string; + skins?: Array>; +}; diff --git a/packages/frontend/component/src/ui/icon-picker/picker/picker.css.ts b/packages/frontend/component/src/ui/icon-picker/picker/picker.css.ts new file mode 100644 index 0000000000..8c47b76c75 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/picker/picker.css.ts @@ -0,0 +1,69 @@ +import { cssVarV2 } from '@toeverything/theme/v2'; +import { style } from '@vanilla-extract/css'; + +export const root = style({ + height: '100%', + display: 'flex', + flexDirection: 'column', +}); + +// search + +export const searchContainer = style({ + padding: '16px 12px 8px 12px', + display: 'flex', + gap: 8, +}); + +export const searchInput = style({ + width: 0, + flexGrow: 1, + height: `32px !important`, + borderRadius: `4px !important`, + gap: `0px !important`, +}); + +// content scroll +export const scrollRoot = style({ + height: 0, + flexGrow: 1, + padding: '0px 12px', +}); + +export const scrollViewport = style({ + padding: '8px 0px', +}); + +// group +export const group = style({ + selectors: { + '&:not(:last-child)': { + marginBottom: 8, + }, + }, +}); + +export const groupName = style({ + fontSize: 12, + fontWeight: 500, + lineHeight: '18px', + color: cssVarV2.text.secondary, + height: 30, + display: 'flex', + alignItems: 'center', + padding: '0px 4px', +}); + +export const groupGrid = style({ + display: 'flex', + flexWrap: 'wrap', + justifyContent: 'space-between', + gap: 4, + + // fill the last row with empty space + '::after': { + content: '""', + flex: 'auto', + minWidth: '24px', + }, +}); diff --git a/packages/frontend/component/src/ui/icon-picker/renderer.tsx b/packages/frontend/component/src/ui/icon-picker/renderer.tsx new file mode 100644 index 0000000000..f8a93cc23d --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/renderer.tsx @@ -0,0 +1,18 @@ +import { AffineIconRenderer } from './renderer/affine-icon'; + +export const IconRenderer = ({ + iconType, + icon, +}: { + iconType: 'emoji' | 'affine-icon'; + icon: string; +}) => { + if (iconType === 'emoji') { + return icon; + } + if (iconType === 'affine-icon') { + return ; + } + + return null; +}; diff --git a/packages/frontend/component/src/ui/icon-picker/renderer/affine-icon.tsx b/packages/frontend/component/src/ui/icon-picker/renderer/affine-icon.tsx new file mode 100644 index 0000000000..0e59476bdb --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/renderer/affine-icon.tsx @@ -0,0 +1,19 @@ +import * as allIcons from '@blocksuite/icons/rc'; +import type { SVGProps } from 'react'; + +export const AffineIconRenderer = ({ + name, + ...props +}: { + name: string; +} & SVGProps) => { + const Icon = allIcons[ + `${name}Icon` as keyof typeof allIcons + ] as React.ComponentType>; + + if (!Icon) { + return null; + } + + return ; +}; diff --git a/packages/frontend/core/package.json b/packages/frontend/core/package.json index 2f1d20bcb6..7312a843a1 100644 --- a/packages/frontend/core/package.json +++ b/packages/frontend/core/package.json @@ -24,7 +24,7 @@ "@blocksuite/affine-components": "workspace:*", "@blocksuite/affine-shared": "workspace:*", "@blocksuite/global": "workspace:*", - "@blocksuite/icons": "^2.2.13", + "@blocksuite/icons": "^2.2.17", "@blocksuite/std": "workspace:*", "@dotlottie/player-component": "^2.7.12", "@emotion/cache": "^11.14.0", diff --git a/yarn.lock b/yarn.lock index 393e9ea5b7..dbeb6a867a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -184,7 +184,7 @@ __metadata: "@affine/error": "workspace:*" "@affine/graphql": "workspace:*" "@affine/routes": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@radix-ui/react-accordion": "npm:^1.2.2" "@radix-ui/react-alert-dialog": "npm:^1.1.3" "@radix-ui/react-aspect-ratio": "npm:^1.1.1" @@ -253,7 +253,7 @@ __metadata: "@affine/i18n": "workspace:*" "@affine/nbstore": "workspace:*" "@blocksuite/affine": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@capacitor/android": "npm:^7.0.0" "@capacitor/app": "npm:^7.0.0" "@capacitor/cli": "npm:^7.0.0" @@ -312,7 +312,7 @@ __metadata: "@atlaskit/pragmatic-drag-and-drop": "npm:^1.4.0" "@atlaskit/pragmatic-drag-and-drop-hitbox": "npm:^1.0.3" "@blocksuite/affine": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@chromatic-com/storybook": "npm:^4.0.0" "@emoji-mart/data": "npm:^1.2.1" "@emoji-mart/react": "npm:^1.1.1" @@ -348,6 +348,7 @@ __metadata: clsx: "npm:^2.1.1" dayjs: "npm:^1.11.13" emoji-mart: "npm:^5.6.0" + emojibase-data: "npm:^16.0.3" foxact: "npm:^0.2.45" jotai: "npm:^2.10.3" lit: "npm:^3.2.1" @@ -409,7 +410,7 @@ __metadata: "@blocksuite/affine-ext-loader": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.13" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@dotlottie/player-component": "npm:^2.7.12" "@emotion/cache": "npm:^11.14.0" @@ -687,7 +688,7 @@ __metadata: "@affine/native": "workspace:*" "@affine/nbstore": "workspace:*" "@blocksuite/affine": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@capacitor/app": "npm:^7.0.0" "@capacitor/browser": "npm:^7.0.0" "@capacitor/cli": "npm:^7.0.0" @@ -754,7 +755,7 @@ __metadata: "@affine/i18n": "workspace:*" "@affine/nbstore": "workspace:*" "@blocksuite/affine": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@sentry/react": "npm:^9.2.0" "@toeverything/infra": "workspace:*" "@types/react": "npm:^19.0.1" @@ -2434,7 +2435,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2462,7 +2463,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -2489,7 +2490,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@emoji-mart/data": "npm:^1.2.1" @@ -2522,7 +2523,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2550,7 +2551,7 @@ __metadata: "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/data-view": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2580,7 +2581,7 @@ __metadata: "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/data-view": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@emotion/css": "npm:^11.13.5" @@ -2636,7 +2637,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2664,7 +2665,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2696,7 +2697,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2727,7 +2728,7 @@ __metadata: "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/affine-widget-frame-title": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2756,7 +2757,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2784,7 +2785,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2814,7 +2815,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2846,7 +2847,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -2921,7 +2922,7 @@ __metadata: "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/data-view": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -2953,7 +2954,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3013,7 +3014,7 @@ __metadata: "@blocksuite/affine-widget-slash-menu": "workspace:*" "@blocksuite/data-view": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@emotion/css": "npm:^11.13.5" @@ -3033,7 +3034,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@blocksuite/sync": "workspace:*" @@ -3081,7 +3082,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/data-view": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3106,7 +3107,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3130,7 +3131,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3156,7 +3157,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3184,7 +3185,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3211,7 +3212,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3240,7 +3241,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3269,7 +3270,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3300,7 +3301,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3335,7 +3336,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3367,7 +3368,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3395,7 +3396,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3424,7 +3425,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3453,7 +3454,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3482,7 +3483,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-toolbar": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -3544,7 +3545,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3575,7 +3576,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3609,7 +3610,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3637,7 +3638,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3672,7 +3673,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3706,7 +3707,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3750,7 +3751,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3775,7 +3776,7 @@ __metadata: dependencies: "@blocksuite/affine-model": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3834,7 +3835,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -3861,7 +3862,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@preact/signals-core": "npm:^1.8.0" "@toeverything/theme": "npm:^1.1.16" @@ -3881,7 +3882,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" @@ -3907,7 +3908,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" @@ -3929,7 +3930,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" "@lit/context": "npm:^1.1.2" @@ -3952,7 +3953,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" "@preact/signals-core": "npm:^1.8.0" @@ -4011,7 +4012,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/data-view": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -4037,7 +4038,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -4064,7 +4065,7 @@ __metadata: "@blocksuite/affine-shared": "workspace:*" "@blocksuite/affine-widget-edgeless-selected-rect": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@lit/context": "npm:^1.1.2" "@preact/signals-core": "npm:^1.8.0" @@ -4084,7 +4085,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@lit/context": "npm:^1.1.2" @@ -4108,7 +4109,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@preact/signals-core": "npm:^1.8.0" "@toeverything/theme": "npm:^1.1.16" @@ -4144,7 +4145,7 @@ __metadata: "@blocksuite/affine-rich-text": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" @@ -4169,7 +4170,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" "@preact/signals-core": "npm:^1.8.0" @@ -4190,7 +4191,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@floating-ui/dom": "npm:^1.6.13" "@preact/signals-core": "npm:^1.8.0" @@ -4299,7 +4300,7 @@ __metadata: "@blocksuite/affine-components": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/global": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/std": "workspace:*" "@blocksuite/store": "workspace:*" "@emotion/css": "npm:^11.13.5" @@ -4333,9 +4334,9 @@ __metadata: languageName: unknown linkType: soft -"@blocksuite/icons@npm:^2.2.12, @blocksuite/icons@npm:^2.2.13": - version: 2.2.15 - resolution: "@blocksuite/icons@npm:2.2.15" +"@blocksuite/icons@npm:^2.2.17": + version: 2.2.17 + resolution: "@blocksuite/icons@npm:2.2.17" peerDependencies: "@types/react": ^18.0.25 change-case: 4.1.2 @@ -4346,7 +4347,7 @@ __metadata: optional: true react: optional: true - checksum: 10/891c646b5a1c5ee8f4e42752053a7aab7e55ed8f6f6a08e0fe9371172c92ad5b861355d017175426871a422f6364a8d18aa88a1f96aa33029bf2a48d33f70c40 + checksum: 10/a9f0f96507bb1df537479d59693f6468f230e5b18bcab9fcfb62458650ee9ccf7d0972fb21029ad9594f7f312b5f92692ad5acff9a7281bc5288351769d73409 languageName: node linkType: hard @@ -4355,7 +4356,7 @@ __metadata: resolution: "@blocksuite/integration-test@workspace:blocksuite/integration-test" dependencies: "@blocksuite/affine": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@floating-ui/dom": "npm:^1.6.13" "@lit/context": "npm:^1.1.3" "@lottiefiles/dotlottie-wc": "npm:^0.5.0" @@ -4383,7 +4384,7 @@ __metadata: "@blocksuite/affine-model": "workspace:*" "@blocksuite/affine-shared": "workspace:*" "@blocksuite/data-view": "workspace:*" - "@blocksuite/icons": "npm:^2.2.12" + "@blocksuite/icons": "npm:^2.2.17" "@blocksuite/integration-test": "workspace:*" "@preact/signals-core": "npm:^1.8.0" "@shoelace-style/shoelace": "npm:2.20.1" @@ -20950,6 +20951,15 @@ __metadata: languageName: node linkType: hard +"emojibase-data@npm:^16.0.3": + version: 16.0.3 + resolution: "emojibase-data@npm:16.0.3" + peerDependencies: + emojibase: "*" + checksum: 10/d9cd4b961ea5bca483b857bc84e670e77c3dcbeac41ce3b672086a9256a43bc027b34d4adc9f9a2be85e2b76c85a2b5e91280b6518335432bdbd4c671eeba1ec + languageName: node + linkType: hard + "emojis-list@npm:^3.0.0": version: 3.0.0 resolution: "emojis-list@npm:3.0.0" From 2f118206cc8f8d9f04a1b6a147fcd353b4f68a24 Mon Sep 17 00:00:00 2001 From: EYHN Date: Wed, 24 Sep 2025 16:02:47 +0800 Subject: [PATCH 22/28] feat(core): mcp server setting (#13630) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary by CodeRabbit * **New Features** * MCP Server integration available in cloud workspaces with a dedicated settings panel. * Manage personal access tokens: generate/revoke tokens and view revealed token. * One-click copy of a prefilled server configuration JSON. * New query to fetch revealed access tokens. * **Improvements** * Integration list adapts to workspace type (cloud vs. local). * More reliable token refresh with clearer loading, error and revalidation states. * **Localization** * Added “Copied to clipboard” message and MCP Server name/description translations. * **Chores** * Updated icon dependency across many packages. --- .../server/src/core/access-token/resolver.ts | 7 + .../backend/server/src/models/access-token.ts | 3 +- packages/backend/server/src/schema.gql | 1 + .../graphql/src/graphql/access-token/list.gql | 3 +- packages/common/graphql/src/graphql/index.ts | 3 +- packages/common/graphql/src/schema.ts | 6 +- .../integration/constants.tsx | 29 ++- .../workspace-setting/integration/index.tsx | 19 +- .../integration/mcp-server/MCP.inline.svg | 3 + .../mcp-server/setting-panel.css.ts | 48 ++++ .../integration/mcp-server/setting-panel.tsx | 227 ++++++++++++++++++ .../frontend/core/src/modules/cloud/index.ts | 7 +- .../modules/cloud/services/access-token.ts | 80 ++++++ .../src/modules/cloud/stores/access-token.ts | 51 ++++ packages/frontend/i18n/src/i18n.gen.ts | 12 + packages/frontend/i18n/src/resources/en.json | 3 + 16 files changed, 475 insertions(+), 27 deletions(-) create mode 100644 packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/MCP.inline.svg create mode 100644 packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/setting-panel.css.ts create mode 100644 packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/setting-panel.tsx create mode 100644 packages/frontend/core/src/modules/cloud/services/access-token.ts create mode 100644 packages/frontend/core/src/modules/cloud/stores/access-token.ts diff --git a/packages/backend/server/src/core/access-token/resolver.ts b/packages/backend/server/src/core/access-token/resolver.ts index 4bedb252f8..b80a83d27c 100644 --- a/packages/backend/server/src/core/access-token/resolver.ts +++ b/packages/backend/server/src/core/access-token/resolver.ts @@ -50,6 +50,13 @@ export class AccessTokenResolver { return await this.models.accessToken.list(user.id); } + @Query(() => [RevealedAccessToken]) + async revealedAccessTokens( + @CurrentUser() user: CurrentUser + ): Promise { + return await this.models.accessToken.list(user.id, true); + } + @Mutation(() => RevealedAccessToken) async generateUserAccessToken( @CurrentUser() user: CurrentUser, diff --git a/packages/backend/server/src/models/access-token.ts b/packages/backend/server/src/models/access-token.ts index c299f9f1b0..58d1a7fcf9 100644 --- a/packages/backend/server/src/models/access-token.ts +++ b/packages/backend/server/src/models/access-token.ts @@ -15,13 +15,14 @@ export class AccessTokenModel extends BaseModel { super(); } - async list(userId: string) { + async list(userId: string, revealed: boolean = false) { return await this.db.accessToken.findMany({ select: { id: true, name: true, createdAt: true, expiresAt: true, + token: revealed, }, where: { userId, diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index 6db883acca..3f2d10b010 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -1596,6 +1596,7 @@ type Query { """query workspace embedding status""" queryWorkspaceEmbeddingStatus(workspaceId: String!): ContextWorkspaceEmbeddingStatus! + revealedAccessTokens: [RevealedAccessToken!]! """server config""" serverConfig: ServerConfigType! diff --git a/packages/common/graphql/src/graphql/access-token/list.gql b/packages/common/graphql/src/graphql/access-token/list.gql index e3ebeeec8d..13dd31027d 100644 --- a/packages/common/graphql/src/graphql/access-token/list.gql +++ b/packages/common/graphql/src/graphql/access-token/list.gql @@ -1,8 +1,9 @@ query listUserAccessTokens { - accessTokens { + revealedAccessTokens { id name createdAt expiresAt + token } } \ No newline at end of file diff --git a/packages/common/graphql/src/graphql/index.ts b/packages/common/graphql/src/graphql/index.ts index 4ad96df004..4f43d4dbfa 100644 --- a/packages/common/graphql/src/graphql/index.ts +++ b/packages/common/graphql/src/graphql/index.ts @@ -88,11 +88,12 @@ export const listUserAccessTokensQuery = { id: 'listUserAccessTokensQuery' as const, op: 'listUserAccessTokens', query: `query listUserAccessTokens { - accessTokens { + revealedAccessTokens { id name createdAt expiresAt + token } }`, }; diff --git a/packages/common/graphql/src/schema.ts b/packages/common/graphql/src/schema.ts index 325592dfea..07adda5dd1 100644 --- a/packages/common/graphql/src/schema.ts +++ b/packages/common/graphql/src/schema.ts @@ -2166,6 +2166,7 @@ export interface Query { publicUserById: Maybe; /** query workspace embedding status */ queryWorkspaceEmbeddingStatus: ContextWorkspaceEmbeddingStatus; + revealedAccessTokens: Array; /** server config */ serverConfig: ServerConfigType; /** Get user by email */ @@ -3089,12 +3090,13 @@ export type ListUserAccessTokensQueryVariables = Exact<{ export type ListUserAccessTokensQuery = { __typename?: 'Query'; - accessTokens: Array<{ - __typename?: 'AccessToken'; + revealedAccessTokens: Array<{ + __typename?: 'RevealedAccessToken'; id: string; name: string; createdAt: string; expiresAt: string | null; + token: string; }>; }; diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/constants.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/constants.tsx index 619b5eb1bb..23a7e32d6b 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/constants.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/constants.tsx @@ -1,11 +1,11 @@ -import type { FeatureFlagService } from '@affine/core/modules/feature-flag'; import { IntegrationTypeIcon } from '@affine/core/modules/integration'; import type { I18nString } from '@affine/i18n'; import { Logo1Icon, TodayIcon } from '@blocksuite/icons/rc'; -import { LiveData } from '@toeverything/infra'; import type { ReactNode } from 'react'; import { CalendarSettingPanel } from './calendar/setting-panel'; +import MCPIcon from './mcp-server/MCP.inline.svg'; +import { McpServerSettingPanel } from './mcp-server/setting-panel'; import { ReadwiseSettingPanel } from './readwise/setting-panel'; type IntegrationCard = { @@ -13,6 +13,7 @@ type IntegrationCard = { name: I18nString; desc: I18nString; icon: ReactNode; + cloud?: boolean; } & ( | { setting: ReactNode; @@ -37,6 +38,14 @@ const INTEGRATION_LIST = [ icon: , setting: , }, + { + id: 'mcp-server' as const, + name: 'com.affine.integration.mcp-server.name', + desc: 'com.affine.integration.mcp-server.desc', + icon: , + setting: , + cloud: true, + }, { id: 'web-clipper' as const, name: 'com.affine.integration.web-clipper.name', @@ -55,13 +64,11 @@ export type IntegrationItem = Exclude & { id: IntegrationId; }; -export function getAllowedIntegrationList$( - _featureFlagService: FeatureFlagService -) { - return LiveData.computed(() => { - return INTEGRATION_LIST.filter(item => { - if (!item) return false; - return true; - }) as IntegrationItem[]; - }); +export function getAllowedIntegrationList(isCloudWorkspace: boolean) { + return INTEGRATION_LIST.filter(item => { + if (!item) return false; + const requiredCloud = 'cloud' in item && item.cloud; + if (requiredCloud && !isCloudWorkspace) return false; + return true; + }) as IntegrationItem[]; } diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/index.tsx index 5d6e1080e6..7dc9a187c2 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/index.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/index.tsx @@ -1,7 +1,7 @@ import { SettingHeader } from '@affine/component/setting-components'; -import { FeatureFlagService } from '@affine/core/modules/feature-flag'; +import { WorkspaceService } from '@affine/core/modules/workspace'; import { useI18n } from '@affine/i18n'; -import { useLiveData, useService } from '@toeverything/infra'; +import { useService } from '@toeverything/infra'; import { type ReactNode, useCallback, useMemo, useState } from 'react'; import { SubPageProvider, useSubPageIsland } from '../../sub-page'; @@ -10,22 +10,21 @@ import { IntegrationCardContent, IntegrationCardHeader, } from './card'; -import { getAllowedIntegrationList$ } from './constants'; +import { getAllowedIntegrationList } from './constants'; import { type IntegrationItem } from './constants'; import { list } from './index.css'; export const IntegrationSetting = () => { const t = useI18n(); const [opened, setOpened] = useState(null); - const featureFlagService = useService(FeatureFlagService); + const workspaceService = useService(WorkspaceService); + const isCloudWorkspace = workspaceService.workspace.flavour !== 'local'; + console.log('isCloudWorkspace', isCloudWorkspace); - const integrationList = useLiveData( - useMemo( - () => getAllowedIntegrationList$(featureFlagService), - [featureFlagService] - ) + const integrationList = useMemo( + () => getAllowedIntegrationList(isCloudWorkspace), + [isCloudWorkspace] ); - const handleCardClick = useCallback((card: IntegrationItem) => { if ('setting' in card && card.setting) { setOpened(card.id); diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/MCP.inline.svg b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/MCP.inline.svg new file mode 100644 index 0000000000..0b857d323c --- /dev/null +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/MCP.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/setting-panel.css.ts b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/setting-panel.css.ts new file mode 100644 index 0000000000..1cea68d35d --- /dev/null +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/setting-panel.css.ts @@ -0,0 +1,48 @@ +import { cssVar } from '@toeverything/theme'; +import { cssVarV2 } from '@toeverything/theme/v2'; +import { style } from '@vanilla-extract/css'; + +export const connectButton = style({ + width: '100%', + marginTop: '24px', +}); + +export const section = style({ + display: 'flex', + flexDirection: 'column', + border: `1px solid ${cssVar('borderColor')}`, + borderRadius: '8px', + padding: '8px 16px', + gap: '0px', + marginBottom: '16px', +}); + +export const sectionHeader = style({ + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + gap: '8px', +}); + +export const preArea = style({ + backgroundColor: cssVarV2('layer/background/secondary'), + padding: '16px 16px', + borderRadius: '8px', + margin: '8px 0', + fontFamily: cssVar('fontMonoFamily'), + overflowX: 'auto', +}); + +export const sectionDescription = style({ + fontSize: 13, + lineHeight: '22px', + color: cssVarV2('text/secondary'), +}); + +export const sectionTitle = style({ + fontSize: 14, + fontWeight: 500, + lineHeight: 1.25, + color: cssVarV2('text/primary'), +}); diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/setting-panel.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/setting-panel.tsx new file mode 100644 index 0000000000..a7de24543e --- /dev/null +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/mcp-server/setting-panel.tsx @@ -0,0 +1,227 @@ +import { Button, ErrorMessage, notify, Skeleton } from '@affine/component'; +import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; +import { AccessTokenService, ServerService } from '@affine/core/modules/cloud'; +import { WorkspaceService } from '@affine/core/modules/workspace'; +import { UserFriendlyError } from '@affine/error'; +import { useI18n } from '@affine/i18n'; +import { useLiveData, useService } from '@toeverything/infra'; +import { type ReactNode, useEffect, useMemo, useState } from 'react'; + +import { IntegrationSettingHeader } from '../setting'; +import MCPIcon from './MCP.inline.svg'; +import * as styles from './setting-panel.css'; + +export const McpServerSettingPanel = () => { + return ; +}; + +const McpServerSettingHeader = ({ action }: { action?: ReactNode }) => { + const t = useI18n(); + + return ( + } + name={t['com.affine.integration.mcp-server.name']()} + desc={t['com.affine.integration.mcp-server.desc']()} + action={action} + /> + ); +}; + +const McpServerSetting = () => { + const workspaceService = useService(WorkspaceService); + const serverService = useService(ServerService); + const workspaceName = useLiveData(workspaceService.workspace.name$); + const accessTokenService = useService(AccessTokenService); + const accessTokens = useLiveData(accessTokenService.accessTokens$); + const isRevalidating = useLiveData(accessTokenService.isRevalidating$); + const error = useLiveData(accessTokenService.error$); + const [mutating, setMutating] = useState(false); + const t = useI18n(); + + const mcpAccessToken = useMemo(() => { + return accessTokens?.find(token => token.name === 'mcp'); + }, [accessTokens]); + + const code = useMemo(() => { + return mcpAccessToken + ? JSON.stringify( + { + mcpServers: { + [`${workspaceName} - AFFiNE`]: { + type: 'streamable-http', + url: `${serverService.server.baseUrl}/api/workspaces/${workspaceService.workspace.id}/mcp`, + note: 'Read docs from AFFiNE workspace', + headers: { + Authorization: `Bearer ${mcpAccessToken.token}`, + }, + }, + }, + }, + null, + 2 + ) + : null; + }, [mcpAccessToken, workspaceName, workspaceService, serverService]); + + const showLoading = accessTokens === null && isRevalidating; + const showError = accessTokens === null && error !== null; + + useEffect(() => { + accessTokenService.revalidate(); + }, [accessTokenService]); + + const handleGenerateAccessToken = useAsyncCallback(async () => { + setMutating(true); + try { + if (mcpAccessToken) { + await accessTokenService.revokeUserAccessToken(mcpAccessToken.id); + } + await accessTokenService.generateUserAccessToken('mcp'); + } catch (err) { + notify.error({ + error: UserFriendlyError.fromAny(err), + }); + } finally { + setMutating(false); + } + }, [accessTokenService, mcpAccessToken]); + + const handleRevokeAccessToken = useAsyncCallback(async () => { + setMutating(true); + try { + if (mcpAccessToken) { + await accessTokenService.revokeUserAccessToken(mcpAccessToken.id); + } + } catch (err) { + notify.error({ + error: UserFriendlyError.fromAny(err), + }); + } finally { + setMutating(false); + } + }, [accessTokenService, mcpAccessToken]); + + if (showLoading) { + return ( +
+ + +
+ ); + } + + if (showError) { + return ( +
+ + {error} +
+ ); + } + + return ( +
+ + +
+
+
Personal access token
+ {!mcpAccessToken ? ( + + ) : ( + + )} +
+

+ This access token is used for the MCP service, please keep this + information secure. Deleting it will invalidate the access token. +

+
+ +
+
+
Server Config
+ +
+ {code ? ( +
{code}
+ ) : ( +

+ No access token found, please generate one first. +

+ )} +
+ +
+
+
Support tools
+
+
+ +
+
+
doc-read
+
+
+ Return the complete text and basic metadata of a single document + identified by docId; use this when the user needs the full content + of a specific file rather than a search result. +
+
+ +
+
+
doc-semantic-search
+
+
+ Retrieve conceptually related passages by performing vector-based + semantic similarity search across embedded documents; use this tool + only when exact keyword search fails or the user explicitly needs + meaning-level matches (e.g., paraphrases, synonyms, broader + concepts, recent documents). +
+
+ +
+
+
doc-keyword-search
+
+
+ Fuzzy search all workspace documents for the exact keyword or phrase + supplied and return passages ranked by textual match. Use this tool + by default whenever a straightforward term-based or keyword-base + lookup is sufficient. +
+
+
+
+ ); +}; diff --git a/packages/frontend/core/src/modules/cloud/index.ts b/packages/frontend/core/src/modules/cloud/index.ts index 04a6d0ab59..adedec6f7c 100644 --- a/packages/frontend/core/src/modules/cloud/index.ts +++ b/packages/frontend/core/src/modules/cloud/index.ts @@ -7,6 +7,7 @@ export { AccountLoggedOut } from './events/account-logged-out'; export { AuthProvider } from './provider/auth'; export { ValidatorProvider } from './provider/validator'; export { ServerScope } from './scopes/server'; +export { AccessTokenService } from './services/access-token'; export { AuthService } from './services/auth'; export { CaptchaService } from './services/captcha'; export { DefaultServerService } from './services/default-server'; @@ -102,6 +103,8 @@ import { WorkspacePermissionService } from '../permissions'; import { DocScope, DocService, DocsService } from '../doc'; import { DocCreatedByUpdatedBySyncStore } from './stores/doc-created-by-updated-by-sync'; import { GlobalDialogService } from '../dialogs'; +import { AccessTokenService } from './services/access-token'; +import { AccessTokenStore } from './stores/access-token'; export function configureCloudModule(framework: Framework) { configureDefaultAuthProvider(framework); @@ -171,7 +174,9 @@ export function configureCloudModule(framework: Framework) { .service(PublicUserService, [PublicUserStore]) .store(PublicUserStore, [GraphQLService]) .service(UserSettingsService, [UserSettingsStore]) - .store(UserSettingsStore, [GraphQLService]); + .store(UserSettingsStore, [GraphQLService]) + .service(AccessTokenService, [AccessTokenStore]) + .store(AccessTokenStore, [GraphQLService]); framework .scope(WorkspaceScope) diff --git a/packages/frontend/core/src/modules/cloud/services/access-token.ts b/packages/frontend/core/src/modules/cloud/services/access-token.ts new file mode 100644 index 0000000000..2ed4b124ff --- /dev/null +++ b/packages/frontend/core/src/modules/cloud/services/access-token.ts @@ -0,0 +1,80 @@ +import { + effect, + exhaustMapWithTrailing, + fromPromise, + LiveData, + onComplete, + OnEvent, + onStart, + Service, + smartRetry, +} from '@toeverything/infra'; +import { catchError, EMPTY, tap } from 'rxjs'; + +import { AccountChanged } from '../events/account-changed'; +import type { AccessToken, AccessTokenStore } from '../stores/access-token'; + +@OnEvent(AccountChanged, e => e.onAccountChanged) +export class AccessTokenService extends Service { + constructor(private readonly accessTokenStore: AccessTokenStore) { + super(); + } + + accessTokens$ = new LiveData(null); + isRevalidating$ = new LiveData(false); + error$ = new LiveData(null); + + async generateUserAccessToken(name: string) { + const accessToken = + await this.accessTokenStore.generateUserAccessToken(name); + this.accessTokens$.value = [ + ...(this.accessTokens$.value || []), + accessToken as AccessToken, + ]; + + await this.waitForRevalidation(); + } + + async revokeUserAccessToken(id: string) { + await this.accessTokenStore.revokeUserAccessToken(id); + this.accessTokens$.value = + this.accessTokens$.value?.filter(token => token.id !== id) ?? null; + await this.waitForRevalidation(); + } + + revalidate = effect( + exhaustMapWithTrailing(() => { + return fromPromise(() => { + return this.accessTokenStore.listUserAccessTokens(); + }).pipe( + smartRetry(), + tap(accessTokens => { + this.accessTokens$.value = accessTokens; + }), + catchError(error => { + this.error$.value = error; + return EMPTY; + }), + onStart(() => { + this.isRevalidating$.value = true; + }), + onComplete(() => { + this.isRevalidating$.value = false; + }) + ); + }) + ); + + private onAccountChanged() { + this.accessTokens$.value = null; + this.revalidate(); + } + + async waitForRevalidation(signal?: AbortSignal) { + this.revalidate(); + await this.isRevalidating$.waitFor( + isRevalidating => !isRevalidating, + signal + ); + } +} diff --git a/packages/frontend/core/src/modules/cloud/stores/access-token.ts b/packages/frontend/core/src/modules/cloud/stores/access-token.ts new file mode 100644 index 0000000000..d1d5d95f3d --- /dev/null +++ b/packages/frontend/core/src/modules/cloud/stores/access-token.ts @@ -0,0 +1,51 @@ +import { + generateUserAccessTokenMutation, + type ListUserAccessTokensQuery, + listUserAccessTokensQuery, + revokeUserAccessTokenMutation, +} from '@affine/graphql'; +import { Store } from '@toeverything/infra'; + +import type { GraphQLService } from '../services/graphql'; + +export type AccessToken = + ListUserAccessTokensQuery['revealedAccessTokens'][number]; + +export class AccessTokenStore extends Store { + constructor(private readonly gqlService: GraphQLService) { + super(); + } + + async listUserAccessTokens(signal?: AbortSignal): Promise { + const data = await this.gqlService.gql({ + query: listUserAccessTokensQuery, + context: { signal }, + }); + + return data.revealedAccessTokens; + } + + async generateUserAccessToken( + name: string, + expiresAt?: string, + signal?: AbortSignal + ) { + const data = await this.gqlService.gql({ + query: generateUserAccessTokenMutation, + variables: { input: { name, expiresAt } }, + context: { signal }, + }); + + return data.generateUserAccessToken; + } + + async revokeUserAccessToken(id: string, signal?: AbortSignal) { + const data = await this.gqlService.gql({ + query: revokeUserAccessTokenMutation, + variables: { id }, + context: { signal }, + }); + + return data.revokeUserAccessToken; + } +} diff --git a/packages/frontend/i18n/src/i18n.gen.ts b/packages/frontend/i18n/src/i18n.gen.ts index 2c9c0765fe..d9dbd536c9 100644 --- a/packages/frontend/i18n/src/i18n.gen.ts +++ b/packages/frontend/i18n/src/i18n.gen.ts @@ -99,6 +99,10 @@ export function useAFFiNEI18N(): { * `Copied link to clipboard` */ ["Copied link to clipboard"](): string; + /** + * `Copied to clipboard` + */ + ["Copied to clipboard"](): string; /** * `Copy` */ @@ -8180,6 +8184,14 @@ export function useAFFiNEI18N(): { ["com.affine.integration.calendar.unsubscribe-content"](options: { readonly name: string; }): string; + /** + * `MCP Server` + */ + ["com.affine.integration.mcp-server.name"](): string; + /** + * `Enable other MCP Client to search and read the doc of AFFiNE.` + */ + ["com.affine.integration.mcp-server.desc"](): string; /** * `Notes` */ diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index 5fa6256f86..a50e399622 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -15,6 +15,7 @@ "Continue": "Continue", "Convert to ": "Convert to ", "Copied link to clipboard": "Copied link to clipboard", + "Copied to clipboard": "Copied to clipboard", "Copy": "Copy", "Create": "Create", "Created": "Created", @@ -2053,6 +2054,8 @@ "com.affine.integration.calendar.show-events-desc": "Enabling this setting allows you to connect your calendar events to your Journal in AFFiNE", "com.affine.integration.calendar.show-all-day-events": "Show all day event", "com.affine.integration.calendar.unsubscribe-content": "Are you sure you want to unsubscribe \"{{name}}\"? Unsubscribing this account will remove its data from Journal.", + "com.affine.integration.mcp-server.name": "MCP Server", + "com.affine.integration.mcp-server.desc": "Enable other MCP Client to search and read the doc of AFFiNE.", "com.affine.audio.notes": "Notes", "com.affine.audio.transcribing": "Transcribing", "com.affine.audio.transcribe.non-owner.confirm.title": "Unable to retrieve AI results for others", From 3c9d17c983fb6ae63d730f1ffedf6185392add9d Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Wed, 24 Sep 2025 16:29:03 +0800 Subject: [PATCH 23/28] feat(core): insert artifact as code block (#13641) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### PR Dependency Tree * **PR #13641** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) ## Summary by CodeRabbit * **New Features** * Insert HTML content directly into the document as a code block with preview enabled. * Default view changed from Code to Preview for faster content inspection. * New “Insert” action replaces the previous “Download” action to add content into the document. * Added a dedicated “Download HTML” button with an icon to save the HTML file. * Toast notifications confirm successful insertions; errors are reported if insertion fails. * Updated button labeling to reflect the new workflow. --- .../ai/components/ai-tools/code-artifact.ts | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/code-artifact.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/code-artifact.ts index 17361f3512..f19b75406b 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/code-artifact.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/code-artifact.ts @@ -7,11 +7,13 @@ import { type BlockSnapshot, nanoid, type SliceSnapshot, + Text, } from '@blocksuite/affine/store'; import type { NotificationService } from '@blocksuite/affine-shared/services'; import { CodeBlockIcon, CopyIcon, + DownloadIcon, PageIcon, ToolIcon, } from '@blocksuite/icons/lit'; @@ -22,6 +24,7 @@ import { property, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { bundledLanguagesInfo, type ThemedToken } from 'shiki'; +import { preprocessHtml } from '../../utils/html'; import { ArtifactTool } from './artifact-tool'; import type { ToolError } from './type'; @@ -460,7 +463,7 @@ export class CodeArtifactTool extends ArtifactTool< accessor notificationService!: NotificationService; @state() - private accessor mode: 'preview' | 'code' = 'code'; + private accessor mode: 'preview' | 'code' = 'preview'; /* ---------------- ArtifactTool hooks ---------------- */ @@ -567,6 +570,25 @@ export class CodeArtifactTool extends ArtifactTool< } }; + const insertHtmlBlockToEnd = () => { + try { + const store = this.std?.store; + if (!store) return; + const notes = store.getBlocksByFlavour('affine:note'); + const parentId = notes.length > 0 ? notes[0].id : store.root?.id; + if (!parentId) return; + const html = preprocessHtml(htmlContent); + store.addBlock( + 'affine:code', + { text: new Text(html), language: 'html', preview: true }, + parentId + ); + this.notificationService.toast('Inserted to current doc'); + } catch (e) { + console.error(e); + } + }; + const setCodeMode = () => { if (this.mode !== 'code') { this.mode = 'code'; @@ -603,14 +625,17 @@ export class CodeArtifactTool extends ArtifactTool<
- + + ${DownloadIcon({ width: '20', height: '20' })} + ${CopyIcon({ width: '20', height: '20' })} From 7a90e1551ca1a593f042a5f8bbaab4b94092f25c Mon Sep 17 00:00:00 2001 From: Lakr <25259084+Lakr233@users.noreply.github.com> Date: Thu, 25 Sep 2025 12:50:12 +0800 Subject: [PATCH 24/28] fix(ios): complete iap user interface (#13639) ## Summary by CodeRabbit - New Features - In-app purchases fully integrated for Pro and AI plans with restore, live product loading, and StoreKit test configuration. - Improvements - Refreshed paywall: intro animation, delayed close button, smoother horizontal paging, page dots interaction, per-item reveal animations, and purchase-state UI (disabled/checked when owned). - Changes - "Believer" plan and related screens removed; Pro simplified to Monthly and Annual offerings. - Chores - iOS project and build settings updated for newer toolchain and StoreKit support. --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../ios/App/App.xcodeproj/project.pbxproj | 22 ++- .../xcshareddata/xcschemes/AFFiNE.xcscheme | 2 +- .../xcshareddata/xcschemes/App.xcscheme | 5 +- .../ios/App/App/AffineViewController.swift | 25 +++ .../apps/ios/App/App/Products.storekit | 144 ++++++++++++++++++ .../AI/OffsetObservingScrollView.swift | 36 +++++ .../Components/AI/PositionObservingView.swift | 37 +++++ .../AI/SKUnitIntelligentDetailView.swift | 39 +++-- .../Believer/SKUnitBelieverDetailView.swift | 36 ----- .../Components/CategorySelectionView.swift | 1 - .../Components/Components/HeadlineView.swift | 2 +- ...tionView.swift => PackageOptionView.swift} | 12 +- .../Components/PurchaseFooterView.swift | 53 +++++-- .../Components/TheGiveMeMoneyButtonView.swift | 57 ++++--- .../Components/Pro/ProFeaturesCardView.swift | 65 -------- .../Components/Pro/SKUnitProDetailView.swift | 71 +++++++-- .../Sources/AffinePaywall/Model/Feature.swift | 2 +- .../AffinePaywall/Model/SKUnit+AI.swift | 8 +- .../AffinePaywall/Model/SKUnit+Believer.swift | 27 ---- .../AffinePaywall/Model/SKUnit+Pro.swift | 60 ++------ .../Sources/AffinePaywall/Model/SKUnit.swift | 7 +- .../AffinePaywall/Model/SKUnitCategory.swift | 2 - ...Option.swift => SKUnitPackageOption.swift} | 16 +- .../Model/SKUnitSubcategoryProPlan.swift | 30 ---- .../Sources/AffinePaywall/Model/Store.swift | 59 +++++++ .../Model/ViewModel+Action.swift | 108 ++++++++++++- .../Model/ViewModel+Preview.swift | 6 - .../AffinePaywall/Model/ViewModel.swift | 55 ++++--- .../Page/AffinePaywallPageView.swift | 27 +++- .../Sources/AffinePaywall/Paywall.swift | 14 +- .../AffinePaywall/Utils/ViewOffsetKey.swift | 16 -- 31 files changed, 697 insertions(+), 347 deletions(-) create mode 100644 packages/frontend/apps/ios/App/App/Products.storekit create mode 100644 packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/OffsetObservingScrollView.swift create mode 100644 packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/PositionObservingView.swift delete mode 100644 packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Believer/SKUnitBelieverDetailView.swift rename packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/{PricingOptionView.swift => PackageOptionView.swift} (95%) delete mode 100644 packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Pro/ProFeaturesCardView.swift delete mode 100644 packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+Believer.swift rename packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/{SKUnitPricingOption.swift => SKUnitPackageOption.swift} (62%) create mode 100644 packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/Store.swift delete mode 100644 packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Utils/ViewOffsetKey.swift diff --git a/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj b/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj index 24072788cf..451bb06829 100644 --- a/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj +++ b/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 5075136A2D1924C600AD60C0 /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507513692D1924C600AD60C0 /* RootViewController.swift */; }; 50A285D72D112A5E000D5A6D /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 50A285D62D112A5E000D5A6D /* Localizable.xcstrings */; }; 50A285D82D112A5E000D5A6D /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 50A285D52D112A5E000D5A6D /* InfoPlist.xcstrings */; }; + 50A485DE2E840A8000F220CE /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50A485DD2E840A8000F220CE /* StoreKit.framework */; }; 50FF428A2D2E757E0050AA83 /* ApplicationBridgedWindowScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50FF42892D2E757E0050AA83 /* ApplicationBridgedWindowScript.swift */; }; 50FF428C2D2E77CC0050AA83 /* AffineViewController+AIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50FF428B2D2E77CC0050AA83 /* AffineViewController+AIButton.swift */; }; 9D52FC432D26CDBF00105D0A /* JSValueContainerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D52FC422D26CDB600105D0A /* JSValueContainerExt.swift */; }; @@ -57,6 +58,8 @@ 50802D5E2D112F7D00694021 /* Intelligents */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Intelligents; sourceTree = ""; }; 50A285D52D112A5E000D5A6D /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = ""; }; 50A285D62D112A5E000D5A6D /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; + 50A485DD2E840A8000F220CE /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + 50BBC54E2E840DBC0067C5E2 /* Products.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Products.storekit; sourceTree = ""; }; 50CECF1E2E7C1084004487AA /* AffineResources */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = AffineResources; sourceTree = ""; }; 50FF42892D2E757E0050AA83 /* ApplicationBridgedWindowScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationBridgedWindowScript.swift; sourceTree = ""; }; 50FF428B2D2E77CC0050AA83 /* AffineViewController+AIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AffineViewController+AIButton.swift"; sourceTree = ""; }; @@ -96,6 +99,7 @@ buildActionMask = 2147483647; files = ( 5027D47A2E7C5FC100ADD25A /* AffineResources in Frameworks */, + 50A485DE2E840A8000F220CE /* StoreKit.framework in Frameworks */, 5027D4782E7C5FBD00ADD25A /* AffinePaywall in Frameworks */, 9DFCD1462D27D1D70028C92B /* libaffine_mobile_native.a in Frameworks */, 5027D47C2E7C5FC400ADD25A /* AffineGraphQL in Frameworks */, @@ -110,6 +114,7 @@ 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = { isa = PBXGroup; children = ( + 50A485DD2E840A8000F220CE /* StoreKit.framework */, C4C97C6B2D03027900BC2AD1 /* libaffine_mobile_native.a */, 9DFCD1452D27D1D70028C92B /* libaffine_mobile_native.a */, BF48636D7DB5BEE00770FD9A /* Pods_AFFiNE.framework */, @@ -174,6 +179,7 @@ 50FF428B2D2E77CC0050AA83 /* AffineViewController+AIButton.swift */, 50FF42892D2E757E0050AA83 /* ApplicationBridgedWindowScript.swift */, 5027D47F2E7C611900ADD25A /* Tools.swift */, + 50BBC54E2E840DBC0067C5E2 /* Products.storekit */, 9D90BE1D2CCB9876006677DB /* Assets.xcassets */, 9D90BE1E2CCB9876006677DB /* capacitor.config.json */, 9D90BE1F2CCB9876006677DB /* config.xml */, @@ -232,7 +238,7 @@ attributes = { BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 0920; + LastUpgradeCheck = 2600; TargetAttributes = { 504EC3031FED79650016851F = { CreatedOnToolsVersion = 9.2; @@ -371,6 +377,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -381,6 +388,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -388,8 +396,10 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -422,6 +432,7 @@ ONLY_ACTIVE_ARCH = YES; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -432,6 +443,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -442,6 +454,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -449,8 +462,10 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -476,6 +491,7 @@ MTL_ENABLE_DEBUG_INFO = NO; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; @@ -491,7 +507,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 12; - DEVELOPMENT_TEAM = 964G86XT2P; + DEVELOPMENT_TEAM = 73YMMDVT2M; INFOPLIST_FILE = App/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; IPHONEOS_DEPLOYMENT_TARGET = 16.5; @@ -527,7 +543,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 12; - DEVELOPMENT_TEAM = 964G86XT2P; + DEVELOPMENT_TEAM = 73YMMDVT2M; INFOPLIST_FILE = App/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; IPHONEOS_DEPLOYMENT_TARGET = 16.5; diff --git a/packages/frontend/apps/ios/App/App.xcodeproj/xcshareddata/xcschemes/AFFiNE.xcscheme b/packages/frontend/apps/ios/App/App.xcodeproj/xcshareddata/xcschemes/AFFiNE.xcscheme index dec463b303..eb1fc1a2a2 100644 --- a/packages/frontend/apps/ios/App/App.xcodeproj/xcshareddata/xcschemes/AFFiNE.xcscheme +++ b/packages/frontend/apps/ios/App/App.xcodeproj/xcshareddata/xcschemes/AFFiNE.xcscheme @@ -1,6 +1,6 @@ + + : View { + var axes: Axis.Set = [.vertical] + var showsIndicators = true + @Binding var offset: CGPoint + @ViewBuilder var content: () -> Content + + private let coordinateSpaceName = UUID() + + var body: some View { + ScrollView(axes, showsIndicators: showsIndicators) { + PositionObservingView( + coordinateSpace: .named(coordinateSpaceName), + position: Binding( + get: { offset }, + set: { newOffset in + offset = CGPoint( + x: -newOffset.x, + y: -newOffset.y + ) + } + ), + content: content + ) + } + .coordinateSpace(name: coordinateSpaceName) + } +} diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/PositionObservingView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/PositionObservingView.swift new file mode 100644 index 0000000000..dd1ebed921 --- /dev/null +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/PositionObservingView.swift @@ -0,0 +1,37 @@ +// +// PositionObservingView.swift +// AffinePaywall +// +// Created by qaq on 9/23/25. +// + +import SwiftUI + +struct PositionObservingView: View { + var coordinateSpace: CoordinateSpace + @Binding var position: CGPoint + @ViewBuilder var content: () -> Content + + var body: some View { + content() + .background(GeometryReader { geometry in + Color.clear.preference( + key: PreferenceKey.self, + value: geometry.frame(in: coordinateSpace).origin + ) + }) + .onPreferenceChange(PreferenceKey.self) { position in + self.position = position + } + } +} + +private extension PositionObservingView { + struct PreferenceKey: SwiftUI.PreferenceKey { + static var defaultValue: CGPoint { .zero } + + static func reduce(value _: inout CGPoint, nextValue _: () -> CGPoint) { + // No-op + } + } +} diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/SKUnitIntelligentDetailView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/SKUnitIntelligentDetailView.swift index b6f0784684..82e0aa9762 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/SKUnitIntelligentDetailView.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/AI/SKUnitIntelligentDetailView.swift @@ -10,11 +10,14 @@ import SwiftUI struct SKUnitIntelligentDetailView: View { @StateObject var viewModel: ViewModel + + @State var detailIndexInSwitching: UUID? = nil @State var detailIndex: Int = 0 { didSet { lastInteractionDate = Date() } } @State var lastInteractionDate: Date = .init() + @State var scrollOffset: CGPoint = .zero let timer = Timer .publish(every: 5, on: .main, in: .common) @@ -28,15 +31,11 @@ struct SKUnitIntelligentDetailView: View { let height = r.size.height let width = r.size.width ScrollViewReader { scrollView in - ScrollView(.horizontal, showsIndicators: false) { - GeometryReader { geometry in - Color.clear - .preference( - key: ViewOffsetKey.self, - value: geometry.frame(in: .named("scrollView")).origin - ) - } - .frame(width: 0, height: 0) + OffsetObservingScrollView( + axes: .horizontal, + showsIndicators: false, + offset: $scrollOffset + ) { HStack(spacing: 0) { ForEach(0 ..< Self.features.count, id: \.self) { featureIndex in let feature = Self.features[featureIndex] @@ -47,13 +46,6 @@ struct SKUnitIntelligentDetailView: View { } } } - .coordinateSpace(name: "scrollView") - .onPreferenceChange(ViewOffsetKey.self) { newValue in - let page = Int(round(-newValue.x / width)) - guard page != detailIndex else { return } - guard page >= 0, page < Self.features.count else { return } - detailIndex = page - } .frame(height: height) .onChange(of: detailIndex) { newValue in withAnimation(.spring) { @@ -61,6 +53,15 @@ struct SKUnitIntelligentDetailView: View { } } } + .onChange(of: scrollOffset) { _ in + guard detailIndexInSwitching == nil else { return } + guard width > 0 else { return } + let offset = scrollOffset.x + let newIndex = Int((offset + width / 2) / width) + if newIndex != detailIndex, + (0 ..< Self.features.count).contains(newIndex) + { detailIndex = newIndex } + } } PageDotsView( @@ -68,6 +69,12 @@ struct SKUnitIntelligentDetailView: View { total: Self.features.count ) { index in detailIndex = index + let token = UUID() + detailIndexInSwitching = token + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + guard detailIndexInSwitching == token else { return } + detailIndexInSwitching = nil + } } } .onReceive(timer) { _ in diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Believer/SKUnitBelieverDetailView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Believer/SKUnitBelieverDetailView.swift deleted file mode 100644 index a16a417743..0000000000 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Believer/SKUnitBelieverDetailView.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// SKUnitBelieverDetailView.swift -// AffinePaywall -// -// Created by qaq on 9/18/25. -// - -import SwiftUI - -struct SKUnitBelieverDetailView: View { - @StateObject var viewModel: ViewModel - - let features: [Feature] = [ - .init("Everything in AFFiNE Pro"), - .init("Life-time Personal usage"), - .init("1TB Cloud Storage"), - ] - - var body: some View { - VStack(spacing: 24) { - HeadlineView(viewModel: viewModel) - Image("BELIVER_ICON", bundle: .module) - .resizable() - .aspectRatio(contentMode: .fit) - ForEach(features.indices, id: \.self) { index in - let feature = features[index] - ProFeatureRowView(feature: feature, index: index) - } - } - } -} - -#Preview { - SKUnitBelieverDetailView(viewModel: .vmPreviewForBeliever) - .padding() -} diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/CategorySelectionView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/CategorySelectionView.swift index 957b6078be..7610284252 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/CategorySelectionView.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/CategorySelectionView.swift @@ -61,7 +61,6 @@ struct CategorySelectionView: View { return VStack(alignment: .leading, spacing: 12) { CategorySelectionView(selectedTab: .pro, onSelect: { _ in }) CategorySelectionView(selectedTab: .ai, onSelect: { _ in }) - CategorySelectionView(selectedTab: .believer, onSelect: { _ in }) Divider() PreviewWrapper() } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/HeadlineView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/HeadlineView.swift index a8939712ad..fbf9e6f137 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/HeadlineView.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/HeadlineView.swift @@ -13,7 +13,7 @@ struct HeadlineView: View { var body: some View { VStack(spacing: 8) { Text(viewModel.selectedUnit.primaryText) - .font(.system(size: 24, weight: .heavy)) + .font(.system(size: 24, weight: .semibold)) .contentTransition(.numericText()) .animation(.spring.speed(2), value: viewModel.category) .padding(.top, 8) diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PricingOptionView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PackageOptionView.swift similarity index 95% rename from packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PricingOptionView.swift rename to packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PackageOptionView.swift index a00058e9b0..d3a89c7e75 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PricingOptionView.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PackageOptionView.swift @@ -1,5 +1,5 @@ // -// PricingOptionView.swift +// PackageOptionView.swift // AffinePaywall // // Created by qaq on 9/18/25. @@ -8,7 +8,7 @@ import AffineResources import SwiftUI -struct PricingOptionView: View { +struct PackageOptionView: View { let price: String let description: String var badge: String @@ -102,12 +102,12 @@ struct PricingOptionView: View { #Preview { VStack(spacing: 16) { HStack(spacing: 16) { - PricingOptionView( + PackageOptionView( price: "$7.99", description: "Monthly", isSelected: false ) {} - PricingOptionView( + PackageOptionView( price: "$6.75", description: "Annually", badge: "Save 15%", @@ -115,13 +115,13 @@ struct PricingOptionView: View { ) {} } HStack(spacing: 16) { - PricingOptionView( + PackageOptionView( price: "$114514", description: "Monthly", badge: "Most Popular", isSelected: true ) {} - PricingOptionView( + PackageOptionView( price: "$6.75", description: "Annually", badge: "Save 15%", diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PurchaseFooterView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PurchaseFooterView.swift index b6e010f9d7..6ce814039c 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PurchaseFooterView.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/PurchaseFooterView.swift @@ -11,36 +11,67 @@ import SwiftUI struct PurchaseFooterView: View { @StateObject var viewModel: ViewModel + var isPurchased: Bool { + let package = viewModel.selectePackageOption + return viewModel.purchasedItems.contains(package.productIdentifier) + } + var body: some View { VStack(spacing: 16) { - if viewModel.availablePricingOptions.count > 1 { + if viewModel.availablePackageOptions.count > 1 { HStack(spacing: 8) { - ForEach(viewModel.availablePricingOptions) { option in - PricingOptionView( + ForEach(viewModel.availablePackageOptions) { option in + PackageOptionView( price: option.price, description: option.description, badge: option.badge ?? "", - isSelected: option.id == viewModel.selectedPricingIdentifier + isSelected: option.id == viewModel.selectedPackageIdentifier ) { - viewModel.select(pricingOption: option) + viewModel.select(packageOption: option) } } } + .disabled(isPurchased) } - TheGiveMeMoneyButtonView( - primaryTitle: viewModel.selectedPricingOption.primaryTitle, - secondaryTitle: viewModel.selectedPricingOption.secondaryTitle, - callback: viewModel.purchase - ) + if viewModel.updating { + TheGiveMeMoneyButtonView( + primaryTitle: "Height Placeholder", + secondaryTitle: "", + isPurchased: false + ) {} + .hidden() + .background(AffineColors.buttonPrimary.color) + .clipShape(RoundedRectangle(cornerRadius: 8)) + .overlay { + ProgressView() + .progressViewStyle(.circular) + } + .transition(.opacity) + } else { + TheGiveMeMoneyButtonView( + primaryTitle: viewModel.selectePackageOption.primaryTitle, + secondaryTitle: viewModel.selectePackageOption.secondaryTitle, + isPurchased: isPurchased, + callback: viewModel.purchase + ) + .transition(.opacity) + } Button(action: viewModel.restore) { - Text("Restore Purchase") + if isPurchased { + Text("Already Purchased") + } else { + Text("Restore Purchase") + } } .font(.system(size: 12)) .buttonStyle(.plain) .foregroundStyle(AffineColors.textSecondary.color) + .opacity(viewModel.products.isEmpty ? 0 : 1) + .disabled(isPurchased) } + .animation(.spring, value: viewModel.updating) } } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/TheGiveMeMoneyButtonView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/TheGiveMeMoneyButtonView.swift index b92b78cfbc..b56fa459a2 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/TheGiveMeMoneyButtonView.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Components/TheGiveMeMoneyButtonView.swift @@ -11,43 +11,55 @@ import SwiftUI struct TheGiveMeMoneyButtonView: View { let primaryTitle: String let secondaryTitle: String + let isPurchased: Bool let callback: () -> Void init( primaryTitle: String = "", secondaryTitle: String = "", + isPurchased: Bool, callback: @escaping () -> Void = {} ) { self.primaryTitle = primaryTitle self.secondaryTitle = secondaryTitle + self.isPurchased = isPurchased self.callback = callback } var body: some View { Button { callback() } label: { - HStack(spacing: 4) { - if !primaryTitle.isEmpty { - Text(primaryTitle) - .bold() - .font(.system(size: 16)) - .contentTransition(.numericText()) - } - if !secondaryTitle.isEmpty { - Text("(\(secondaryTitle))") - .font(.system(size: 12)) - .opacity(0.8) - .contentTransition(.numericText()) + if isPurchased { + Image(systemName: "checkmark") + .foregroundColor(AffineColors.layerPureWhite.color) + .font(.system(size: 16, weight: .bold)) + .padding(12) + } else { + HStack(spacing: 4) { + if !primaryTitle.isEmpty { + Text(primaryTitle) + .bold() + .font(.system(size: 16)) + .contentTransition(.numericText()) + } + if !secondaryTitle.isEmpty { + Text("(\(secondaryTitle))") + .font(.system(size: 12)) + .opacity(0.8) + .contentTransition(.numericText()) + } } + .foregroundColor(AffineColors.layerPureWhite.color) + .padding(12) } - .foregroundColor(AffineColors.layerPureWhite.color) - .padding(12) } .animation(.spring, value: primaryTitle) .animation(.spring, value: secondaryTitle) .buttonStyle(.plain) .frame(maxWidth: .infinity) + .frame(minHeight: 32) .background(AffineColors.buttonPrimary.color) .clipShape(RoundedRectangle(cornerRadius: 8)) + .disabled(isPurchased) } } @@ -57,19 +69,28 @@ struct TheGiveMeMoneyButtonView: View { VStack(spacing: 16) { TheGiveMeMoneyButtonView( primaryTitle: "Upgrade for $6.75 per month", - secondaryTitle: "" + secondaryTitle: "", + isPurchased: false ) TheGiveMeMoneyButtonView( primaryTitle: "Upgrade for $10 per month", - secondaryTitle: "" + secondaryTitle: "", + isPurchased: false ) TheGiveMeMoneyButtonView( primaryTitle: "$8.9 per month", - secondaryTitle: "billed annually" + secondaryTitle: "billed annually", + isPurchased: false ) TheGiveMeMoneyButtonView( primaryTitle: "Upgrade for $499", - secondaryTitle: "" + secondaryTitle: "", + isPurchased: false + ) + TheGiveMeMoneyButtonView( + primaryTitle: "Upgrade for $499", + secondaryTitle: "", + isPurchased: true ) } .padding(32) diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Pro/ProFeaturesCardView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Pro/ProFeaturesCardView.swift deleted file mode 100644 index bf82bf3b70..0000000000 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Pro/ProFeaturesCardView.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// ProFeaturesCardView.swift -// AffinePaywall -// -// Created by qaq on 9/18/25. -// - -import AffineResources -import SwiftUI - -struct ProFeaturesCardView: View { - let features: [Feature] - let headerText: String - - let timer = Timer - .publish(every: 0.08, on: .main, in: .common) - .autoconnect() - @State var animationIndex: Int64 = 0 - - var body: some View { - VStack(alignment: .leading, spacing: 16) { - if !headerText.isEmpty { - Text(headerText) - .font(.system(size: 13)) - .foregroundColor(AffineColors.textSecondary.color) - .padding(.horizontal, 4) - } - - ForEach(Array(features.enumerated()), id: \.element.id) { index, feature in - ProFeatureRowView(feature: feature, index: index) - .opacity(index < animationIndex ? 1 : 0) - } - } - .animation(.spring.speed(2), value: animationIndex) - .onChange(of: features) { _ in animationIndex = 0 } - .onReceive(timer) { _ in animationIndex += 1 } - .clipped() - .padding(16) - .background(AffineColors.layerBackgroundPrimary.color) - .cornerRadius(16) - .shadow(color: AffineColors.layerBorder.color.opacity(0.08), radius: 8, y: 2) - .animation(.spring.speed(2), value: features) - } -} - -#Preview("Pro") { - ProFeaturesCardView(features: SKUnitSubcategoryProPlan.default.features, headerText: SKUnitSubcategoryProPlan.default.headerText) - .padding() - .background(Color.gray.ignoresSafeArea()) -} - -#Preview("Pro team") { - ProFeaturesCardView( - features: SKUnitSubcategoryProPlan.team.features, - headerText: SKUnitSubcategoryProPlan.team.headerText - ) - .padding() - .background(Color.gray.ignoresSafeArea()) -} - -#Preview("Self Hosted") { - ProFeaturesCardView(features: SKUnitSubcategoryProPlan.selfHost.features, headerText: SKUnitSubcategoryProPlan.selfHost.headerText) - .padding() - .background(Color.gray.ignoresSafeArea()) -} diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Pro/SKUnitProDetailView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Pro/SKUnitProDetailView.swift index 7a9e949ca3..5b976fc57c 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Pro/SKUnitProDetailView.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Components/Pro/SKUnitProDetailView.swift @@ -11,35 +11,82 @@ import SwiftUI struct SKUnitProDetailView: View { @StateObject var viewModel: ViewModel - @State var selection: SKUnitSubcategoryProPlan = .default + @State var selection: SKUnitSubcategoryProPlan + @State var headerText: String + @State var features: [Feature] + @State var animationIndex: Int64 = 0 + + let timer = Timer + .publish(every: 0.075, on: .main, in: .common) + .autoconnect() + + init(viewModel: ViewModel) { + _viewModel = .init(wrappedValue: viewModel) + let item = SKUnitSubcategoryProPlan.default + _selection = .init(initialValue: item) + _headerText = .init(initialValue: item.headerText) + _features = .init(initialValue: item.features) + } var body: some View { VStack(spacing: 24) { - Picker("Plan", selection: $selection) { - ForEach(SKUnitSubcategoryProPlan.allCases) { plan in - Text(plan.title).tag(plan) + if SKUnitSubcategoryProPlan.allCases.count > 1 { + Picker("Plan", selection: $selection) { + ForEach(SKUnitSubcategoryProPlan.allCases) { plan in + Text(plan.title).tag(plan) + } + } + .pickerStyle(.segmented) + .onChange(of: selection) { _ in + viewModel.select(subcategory: selection) } - } - .pickerStyle(.segmented) - .onChange(of: selection) { _ in - viewModel.select(subcategory: selection) } HeadlineView(viewModel: viewModel) ScrollView { - ProFeaturesCardView( - features: selection.features, - headerText: selection.headerText - ) + VStack(alignment: .leading, spacing: 16) { + if !headerText.isEmpty { + Text(headerText) + .font(.system(size: 13)) + .foregroundColor(AffineColors.textSecondary.color) + .contentTransition(.numericText()) + .transition(.opacity) + .padding(.horizontal, 4) + } + + ForEach(Array(features.enumerated()), id: \.element.id) { index, feature in + ProFeatureRowView(feature: feature, index: index) + .opacity(index < animationIndex ? 1 : 0) + } + } + .clipped() + .padding(16) + .background(AffineColors.layerBackgroundPrimary.color) + .cornerRadius(16) + .shadow(color: AffineColors.layerBorder.color.opacity(0.08), radius: 8, y: 2) .padding(16) } .padding(-16) + .animation(.spring.speed(2), value: animationIndex) + .onReceive(timer) { _ in animationIndex += 1 } .frame( maxWidth: .infinity, maxHeight: .infinity, alignment: .top ) + .onChange(of: selection) { _ in updateSelectionContents() } + } + } + + func updateSelectionContents() { + let headerText = selection.headerText + if self.headerText != headerText { + self.headerText = headerText + } + let features = selection.features + if self.features != features { + self.features = features } } } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/Feature.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/Feature.swift index a020af78f5..307eb0e2d7 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/Feature.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/Feature.swift @@ -7,7 +7,7 @@ import Foundation -struct Feature: Identifiable, Equatable { +struct Feature: Identifiable, Equatable, Hashable { var id = UUID() var text: String var isHighlighted: Bool // For text like "Everything in AFFINE Pro" diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+AI.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+AI.swift index b812bbf835..3825234942 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+AI.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+AI.swift @@ -13,13 +13,15 @@ extension SKUnit { category: SKUnitCategory.ai, primaryText: "AFFINE AI", secondaryText: "A true multimodal AI copilot.", - pricing: [ - SKUnitPricingOption( + package: [ + SKUnitPackageOption( price: "$8.9 per month", description: "", isDefaultSelected: true, primaryTitle: "$8.9 per month", - secondaryTitle: "billed annually" + secondaryTitle: "billed annually", + productIdentifier: "app.affine.pro.ai.Annual", + revenueCatIdentifier: "app.affine.pro.ai.Annual" ), ] ), diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+Believer.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+Believer.swift deleted file mode 100644 index 92472b3bf4..0000000000 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+Believer.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// SKUnit+Believer.swift -// AffinePaywall -// -// Created by qaq on 9/18/25. -// - -import Foundation - -extension SKUnit { - static let believerUnits: [SKUnit] = [ - SKUnit( - category: SKUnitCategory.believer, - primaryText: "Believer Plan", - secondaryText: "AFFINE's Everything", - pricing: [ - SKUnitPricingOption( - price: "$499", - description: "", - isDefaultSelected: true, - primaryTitle: "Upgrade for $499", - secondaryTitle: "" - ), - ] - ), - ] -} diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+Pro.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+Pro.swift index f2355972f8..3488882cf6 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+Pro.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit+Pro.swift @@ -14,67 +14,25 @@ extension SKUnit { subcategory: SKUnitSubcategoryProPlan.default, primaryText: "Pro", secondaryText: "For family and small teams.", - pricing: [ - SKUnitPricingOption( + package: [ + SKUnitPackageOption( price: "$7.99", description: "Monthly", isDefaultSelected: false, primaryTitle: "Upgrade for $7.99/month", - secondaryTitle: "" + secondaryTitle: "", + productIdentifier: "app.affine.pro.Monthly", + revenueCatIdentifier: "app.affine.pro.Monthly" ), - SKUnitPricingOption( + SKUnitPackageOption( price: "$6.75", description: "Annual", badge: "Save 15%", isDefaultSelected: true, primaryTitle: "Upgrade for $6.75/month", - secondaryTitle: "" - ), - ] - ), - SKUnit( - category: SKUnitCategory.pro, - subcategory: SKUnitSubcategoryProPlan.team, - primaryText: "Pro team", - secondaryText: "Best for scalable teams.", - pricing: [ - SKUnitPricingOption( - price: "$12", - description: "Per seat monthly", - isDefaultSelected: false, - primaryTitle: "Upgrade for $12/month", - secondaryTitle: "" - ), - SKUnitPricingOption( - price: "$10", - description: "Annual", - badge: "Save 15%", - isDefaultSelected: true, - primaryTitle: "Upgrade for $10/month", - secondaryTitle: "" - ), - ] - ), - SKUnit( - category: SKUnitCategory.pro, - subcategory: SKUnitSubcategoryProPlan.selfHost, - primaryText: "Self Hosted team", - secondaryText: "Best for scalable teams.", - pricing: [ - SKUnitPricingOption( - price: "$12", - description: "Per seat monthly", - isDefaultSelected: false, - primaryTitle: "Upgrade for $12/month", - secondaryTitle: "" - ), - SKUnitPricingOption( - price: "$10", - description: "Annual", - badge: "Save 15%", - isDefaultSelected: true, - primaryTitle: "Upgrade for $10/month", - secondaryTitle: "" + secondaryTitle: "", + productIdentifier: "app.affine.pro.Annual", + revenueCatIdentifier: "app.affine.pro.Annual" ), ] ), diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit.swift index 2ef8177ae0..9020c7b3cf 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnit.swift @@ -13,20 +13,20 @@ struct SKUnit: Identifiable, Sendable { let subcategory: any SKUnitSubcategorizable let primaryText: String let secondaryText: String - let pricing: [SKUnitPricingOption] + let package: [SKUnitPackageOption] init( category: SKUnitCategory, subcategory: (any SKUnitSubcategorizable) = SKUnitSingleSubcategory.single, primaryText: String, secondaryText: String, - pricing: [SKUnitPricingOption] + package: [SKUnitPackageOption] ) { self.category = category self.subcategory = subcategory self.primaryText = primaryText self.secondaryText = secondaryText - self.pricing = pricing + self.package = package } } @@ -34,7 +34,6 @@ extension SKUnit { static let allUnits: [SKUnit] = [ proUnits, aiUnits, - believerUnits, ].flatMap(\.self) static func units(for category: SKUnitCategory) -> [SKUnit] { diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitCategory.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitCategory.swift index 40ea3d4ffb..091c16da1a 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitCategory.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitCategory.swift @@ -12,7 +12,6 @@ enum SKUnitCategory: Int, CaseIterable, Equatable, Identifiable { case pro case ai - case believer } extension SKUnitCategory { @@ -20,7 +19,6 @@ extension SKUnitCategory { switch self { case .pro: "AFFINE.Pro" case .ai: "AI" - case .believer: "Believer" } } } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitPricingOption.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitPackageOption.swift similarity index 62% rename from packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitPricingOption.swift rename to packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitPackageOption.swift index 8a790911e3..b3dbfc272d 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitPricingOption.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitPackageOption.swift @@ -1,5 +1,5 @@ // -// SKUnitPricingOption.swift +// SKUnitPackageOption.swift // AffinePaywall // // Created by qaq on 9/18/25. @@ -7,10 +7,10 @@ import Foundation -struct SKUnitPricingOption: Identifiable, Equatable { +struct SKUnitPackageOption: Identifiable, Equatable { var id: UUID - // pricing selection button + // package selection button var price: String var description: String var badge: String? @@ -20,6 +20,10 @@ struct SKUnitPricingOption: Identifiable, Equatable { var primaryTitle: String var secondaryTitle: String + // product identifiers + var productIdentifier: String + var revenueCatIdentifier: String + init( id: UUID = UUID(), price: String, @@ -27,7 +31,9 @@ struct SKUnitPricingOption: Identifiable, Equatable { badge: String? = nil, isDefaultSelected: Bool = false, primaryTitle: String, - secondaryTitle: String + secondaryTitle: String, + productIdentifier: String, + revenueCatIdentifier: String ) { self.id = id self.price = price @@ -36,5 +42,7 @@ struct SKUnitPricingOption: Identifiable, Equatable { self.isDefaultSelected = isDefaultSelected self.primaryTitle = primaryTitle self.secondaryTitle = secondaryTitle + self.productIdentifier = productIdentifier + self.revenueCatIdentifier = revenueCatIdentifier } } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitSubcategoryProPlan.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitSubcategoryProPlan.swift index 78ae59e36d..082ae14d9c 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitSubcategoryProPlan.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/SKUnitSubcategoryProPlan.swift @@ -9,14 +9,10 @@ import Foundation enum SKUnitSubcategoryProPlan: String, SKUnitSubcategorizable { case `default` - case team - case selfHost var title: String { switch self { case .default: "Pro" - case .team: "Pro team" - case .selfHost: "Self Hosted" } } @@ -24,10 +20,6 @@ enum SKUnitSubcategoryProPlan: String, SKUnitSubcategorizable { switch self { case .default: "For family and small teams." - case .team: - "Best for scalable teams." - case .selfHost: - "Best for scalable teams." } } } @@ -37,10 +29,6 @@ extension SKUnitSubcategoryProPlan { switch self { case .default: "Include in Pro" - case .team: - "Include in Team Workspace" - case .selfHost: - "Both in Teams & Enterprise" } } @@ -56,24 +44,6 @@ extension SKUnitSubcategoryProPlan { Feature("Community Support"), Feature("Real-time Syncing & Collaboration for more people"), ] - case .team: - [ - Feature("Everything in AFFINE Pro", isHighlighted: true), - Feature("100 GB initial storage + 20 GB per seat"), - Feature("500 MB of maximum file size"), - Feature("Unlimited team members (10+ seats)"), - Feature("Multiple admin roles"), - Feature("Priority customer support"), - ] - case .selfHost: - [ - Feature("Everything in Self Hosted FOSS"), - Feature("100 GB initial storage + 20 GB per seat"), - Feature("500 MB of maximum file size"), - Feature("Unlimited team members (10+ seats)"), - Feature("Multiple admin roles"), - Feature("Priority customer support"), - ] } } } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/Store.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/Store.swift new file mode 100644 index 0000000000..b9b89f26e5 --- /dev/null +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/Store.swift @@ -0,0 +1,59 @@ +// +// Store.swift +// AffinePaywall +// +// Created by qaq on 9/24/25. +// + +import StoreKit + +let store = Store.shared + +final nonisolated class Store: ObservableObject, Sendable { + static let shared = Store() + + private init() {} + + func fetchAppStoreContents() async throws { + try await AppStore.sync() + } + + func fetchProducts() async throws -> [Product] { + let identifiers = SKUnit.allUnits + .flatMap(\.package) + .map(\.productIdentifier) + print("fetching products for identifiers: \(identifiers)") + let products = try await Product.products( + for: identifiers.map { .init($0) } + ) + if products.count != identifiers.count { + throw NSError(domain: "AffinePaywall", code: -1, userInfo: [ + NSLocalizedDescriptionKey: String(localized: "Failed to fetch all products from App Store."), + ]) + } + return products + } + + func fetchEntitlements() async throws -> Set { + var purchasedItems: Set = [] + + for await result in Transaction.currentEntitlements { + if case let .verified(transaction) = result { + guard transaction.revocationDate == nil else { continue } + + switch transaction.productType { + case .nonConsumable, .consumable: + purchasedItems.insert(transaction.productID) + case .autoRenewable, .nonRenewable: + if let status = await transaction.subscriptionStatus, + status.state == .subscribed + { purchasedItems.insert(transaction.productID) } + default: + break + } + } + } + + return purchasedItems + } +} diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel+Action.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel+Action.swift index 377ae6808d..ff2f843309 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel+Action.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel+Action.swift @@ -6,26 +6,122 @@ // import Foundation +import UIKit extension ViewModel { func purchase() { let unit = selectedUnit - let option = selectedPricingOption + let option = selectePackageOption + assert(!updating) + guard !updating else { return } print(#function, unit, option) + + Task.detached { + await MainActor.run { self.updating = true } + var shouldDismiss = false + + let product = await self.products.first { + $0.id == option.productIdentifier + } + + if let product { + let result = try await product.purchase() + switch result { + case .pending: + break + case let .success(transaction): + print("purchase success", transaction) + shouldDismiss = true + case .userCancelled: + break + @unknown default: + assertionFailure() + } + } else { assertionFailure() } // should never happen + + await MainActor.run { + self.updating = false + if shouldDismiss { self.dismiss() } + } + } } func restore() { let unit = selectedUnit - let option = selectedPricingOption + let option = selectePackageOption + assert(!updating) + guard !updating else { return } print(#function, unit, option) + + updateAppStoreStatus(initial: false) } func dismiss() { - let unit = selectedUnit - let option = selectedPricingOption - - print(#function, unit, option) + print(#function) + associatedController?.dismiss(animated: true) + } +} + +nonisolated extension ViewModel { + func updateAppStoreStatusExecute(initial: Bool) async { + guard await !updating else { return } + guard let controller = await associatedController else { return } + await MainActor.run { self.updating = true } + + do { + // before we continue, sync any changes from App Store + // this will ask user to sign in if needed + do { + try await store.fetchAppStoreContents() + } catch { + // ignore user's cancellation on restore, not a huge deal + print("updateAppStoreItems error:", error) + } + + // now we fetch records from app store + let products = try await store.fetchProducts() + await MainActor.run { self.products = products } + + // fetch purchased items if signed in + do { + let purchase = try await store.fetchEntitlements() + await MainActor.run { self.purchasedItems = purchase } + } catch { + print("fetchEntitlements error:", error) + if !initial { throw error } + } + + // select the package under purchased items if any + let availablePackages = await availablePackageOptions + let purchase = await purchasedItems + let purchasedPackages = availablePackages.filter { + purchase.contains($0.productIdentifier) + } + assert(purchasedPackages.count <= 1) + if let firstPurchased = purchasedPackages.first { + await MainActor.run { + self.select(packageOption: firstPurchased) + } + } + } catch { + await MainActor.run { + let alert = UIAlertController( + title: String(localized: "Error"), + message: error.localizedDescription, + preferredStyle: .alert + ) + alert.addAction( + UIAlertAction( + title: String(localized: "OK"), + style: .default + ) { [self] _ in dismiss() } + ) + controller.present(alert, animated: true) + } + } + + await MainActor.run { self.updating = false } } } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel+Preview.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel+Preview.swift index 9b0a730c91..79286fefa6 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel+Preview.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel+Preview.swift @@ -20,10 +20,4 @@ extension ViewModel { vm.select(category: .ai) return vm }() - - static let vmPreviewForBeliever: ViewModel = { - let vm = ViewModel() - vm.select(category: .believer) - return vm - }() } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel.swift index aa2a52e675..8dd52c2fd4 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Model/ViewModel.swift @@ -5,6 +5,7 @@ // Created by qaq on 9/18/25. // +import StoreKit import SwiftUI @MainActor @@ -15,12 +16,30 @@ class ViewModel: ObservableObject { @Published private(set) var category: SKUnitCategory = .pro @Published private(set) var subcategory: any SKUnitSubcategorizable = SKUnitSubcategoryProPlan.default - @Published private(set) var selectedPricingIdentifier: UUID = SKUnit.unit( + @Published private(set) var selectedPackageIdentifier: UUID = SKUnit.unit( for: .pro, subcategory: SKUnitSubcategoryProPlan.default - )!.pricing.first { $0.isDefaultSelected }!.id + )!.package.first { $0.isDefaultSelected }!.id - init() {} + @Published var updating = false + @Published var products: [Product] = [] + @Published var purchasedItems: Set = [] + + private(set) weak var associatedController: UIViewController? + + init() { + updateAppStoreStatus(initial: true) + } + + func updateAppStoreStatus(initial: Bool) { + Task.detached { + await self.updateAppStoreStatusExecute(initial: initial) + } + } + + func bind(controller: UIViewController) { + associatedController = controller + } func select(category: SKUnitCategory) { self.category = category @@ -30,7 +49,7 @@ class ViewModel: ObservableObject { if !subcategoryExists { subcategory = units.first!.subcategory } - _ = selectedPricingOption // ensure selectedPricingIdentifier is valid + _ = selectePackageOption // ensure selectePackageOption is valid } func select(subcategory: any SKUnitSubcategorizable) { @@ -45,20 +64,20 @@ class ViewModel: ObservableObject { } else { self.subcategory = subcategory } - _ = selectedPricingOption // ensure selectedPricingIdentifier is valid + _ = selectePackageOption // ensure selectePackageOption is valid } - func select(pricingOption option: SKUnitPricingOption) { - selectedPricingIdentifier = option.id + func select(packageOption option: SKUnitPackageOption) { + selectedPackageIdentifier = option.id let unit = availableUnits .first { unit in - unit.pricing.contains { $0.id == option.id } + unit.package.contains { $0.id == option.id } }! category = unit.category subcategory = unit.subcategory - _ = selectedPricingOption // ensure selectedPricingIdentifier is valid + _ = selectePackageOption // ensure selectePackageOption is valid } } @@ -79,21 +98,21 @@ extension ViewModel { return item } - var selectedPricingOption: SKUnitPricingOption { - let item = selectedUnit.pricing - .first { $0.id == selectedPricingIdentifier } + var selectePackageOption: SKUnitPackageOption { + let item = selectedUnit.package + .first { $0.id == selectedPackageIdentifier } if let item { return item } - let defaultItem = selectedUnit.pricing.first { $0.isDefaultSelected } + let defaultItem = selectedUnit.package.first { $0.isDefaultSelected } if let defaultItem { - selectedPricingIdentifier = defaultItem.id + selectedPackageIdentifier = defaultItem.id return defaultItem } - let lastItem = selectedUnit.pricing.last! - selectedPricingIdentifier = lastItem.id + let lastItem = selectedUnit.package.last! + selectedPackageIdentifier = lastItem.id return lastItem } - var availablePricingOptions: [SKUnitPricingOption] { - selectedUnit.pricing + var availablePackageOptions: [SKUnitPackageOption] { + selectedUnit.package } } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Page/AffinePaywallPageView.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Page/AffinePaywallPageView.swift index 9ee871a659..f9a57431f6 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Page/AffinePaywallPageView.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Page/AffinePaywallPageView.swift @@ -13,6 +13,9 @@ struct AffinePaywallPageView: View { @Environment(\.dismiss) var dismiss + @State private var presentAnimation = false + @State private var showCloseButton = false + var body: some View { VStack(alignment: .leading, spacing: 16) { HStack { @@ -24,10 +27,17 @@ struct AffinePaywallPageView: View { Button { viewModel.dismiss() } label: { - Image(AffineIcons.close.rawValue) + AffineIcons.close.image + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 24, height: 24) + .foregroundStyle(.primary) } .buttonStyle(.plain) .foregroundColor(AffineColors.textSecondary.color) + .opacity(showCloseButton ? 1 : 0) + .disabled(!showCloseButton) + .animation(.spring, value: showCloseButton) } ZStack(alignment: .topLeading) { Spacer() @@ -45,11 +55,22 @@ struct AffinePaywallPageView: View { .animation(.spring.speed(2), value: viewModel.category) PurchaseFooterView(viewModel: viewModel) - .animation(.spring.speed(2), value: viewModel.selectedPricingIdentifier) + .animation(.spring.speed(2), value: viewModel.selectedPackageIdentifier) } .padding() + .opacity(presentAnimation ? 1 : 0) + .scaleEffect(presentAnimation ? 1 : 0.95, anchor: .top) + .animation(.spring, value: presentAnimation) + .onAppear { + presentAnimation = true + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + showCloseButton = true + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) .background( AffineColors.layerBackgroundSecondary.color + .ignoresSafeArea() ) } @@ -60,8 +81,6 @@ struct AffinePaywallPageView: View { SKUnitProDetailView(viewModel: viewModel) case .ai: SKUnitIntelligentDetailView(viewModel: viewModel) - case .believer: - SKUnitBelieverDetailView(viewModel: viewModel) } } } diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Paywall.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Paywall.swift index cd4b5b28a0..b0869aac4a 100644 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Paywall.swift +++ b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Paywall.swift @@ -1,12 +1,12 @@ // -// File.swift +// Paywall.swift // AffinePaywall // // Created by qaq on 9/18/25. // -import UIKit import SwiftUI +import UIKit public enum Paywall { @MainActor @@ -15,13 +15,19 @@ public enum Paywall { type: String ) { let viewModel = ViewModel() - switch type { - // TODO: FIGURE OUT PAYWALL TYPES + switch type.lowercased() { + case "pro": + viewModel.select(category: .pro) + viewModel.select(subcategory: SKUnitSubcategoryProPlan.default) + case "ai": + viewModel.select(category: .ai) + viewModel.select(subcategory: SKUnitSingleSubcategory.single) default: break } let view = AffinePaywallPageView(viewModel: viewModel) let hostingController = UIHostingController(rootView: view) + viewModel.bind(controller: hostingController) hostingController.modalPresentationStyle = .overFullScreen hostingController.modalTransitionStyle = .coverVertical hostingController.preferredContentSize = CGSize(width: 555, height: 555) // for iPads diff --git a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Utils/ViewOffsetKey.swift b/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Utils/ViewOffsetKey.swift deleted file mode 100644 index 9e803e3035..0000000000 --- a/packages/frontend/apps/ios/App/Packages/AffinePaywall/Sources/AffinePaywall/Utils/ViewOffsetKey.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// ViewOffsetKey.swift -// AffinePaywall -// -// Created by qaq on 9/18/25. -// - -import SwiftUI - -@MainActor -struct ViewOffsetKey: @MainActor PreferenceKey { - static var defaultValue: CGPoint = .zero - static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) { - value = nextValue() - } -} From 3f9d9fef63f89980ebc7cbd70786c1aa34c5a181 Mon Sep 17 00:00:00 2001 From: DarkSky <25152247+darkskygit@users.noreply.github.com> Date: Fri, 26 Sep 2025 03:00:48 +0800 Subject: [PATCH 25/28] fix(server): rcat event sync (#13648) ## Summary by CodeRabbit - New Features - Subscriptions now include an explicit "trial" flag so trialing users are identified and treated correctly. - Bug Fixes - More robust handling when webhook fields are missing or null. - Improved family-sharing detection to avoid incorrect async processing. - Refactor - Status determination and store resolution simplified to rely on subscription data rather than event payloads. - Tests - Test fixtures updated to include trial and store details for accuracy. --- .../src/__tests__/payment/revenuecat.spec.ts | 21 ++++++++- .../plugins/payment/revenuecat/controller.ts | 19 +++++--- .../src/plugins/payment/revenuecat/service.ts | 33 +++++++------- .../src/plugins/payment/revenuecat/webhook.ts | 45 ++++--------------- 4 files changed, 58 insertions(+), 60 deletions(-) diff --git a/packages/backend/server/src/__tests__/payment/revenuecat.spec.ts b/packages/backend/server/src/__tests__/payment/revenuecat.spec.ts index 35fc095cb3..21f37e9c77 100644 --- a/packages/backend/server/src/__tests__/payment/revenuecat.spec.ts +++ b/packages/backend/server/src/__tests__/payment/revenuecat.spec.ts @@ -179,6 +179,7 @@ test('should standardize RC subscriber response and upsert subscription with obs const subscriber = mockSub([ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-01-01T00:00:00.000Z'), expirationDate: new Date('2026-01-01T00:00:00.000Z'), @@ -245,6 +246,7 @@ test('should process expiration/refund by deleting subscription and emitting can const subscriber = mockSub([ { identifier: 'Pro', + isTrial: false, isActive: false, latestPurchaseDate: new Date('2024-01-01T00:00:00.000Z'), expirationDate: new Date('2024-02-01T00:00:00.000Z'), @@ -341,11 +343,12 @@ test('should activate subscriptions via webhook for whitelisted products across stub: [ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-01-10T00:00:00.000Z'), expirationDate: new Date('2025-02-10T00:00:00.000Z'), productId: 'app.affine.pro.Monthly', - store: 'app_store', + store: 'app_store' as const, willRenew: true, duration: null, }, @@ -363,11 +366,12 @@ test('should activate subscriptions via webhook for whitelisted products across stub: [ { identifier: 'AI', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-03-01T00:00:00.000Z'), expirationDate: new Date('2026-03-01T00:00:00.000Z'), productId: 'app.affine.pro.ai.Annual', - store: 'play_store', + store: 'play_store' as const, willRenew: true, duration: null, }, @@ -419,6 +423,7 @@ test('should keep active and advance period dates when a trialing subscription r [ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-04-01T00:00:00.000Z'), expirationDate: new Date('2025-04-08T00:00:00.000Z'), @@ -431,6 +436,7 @@ test('should keep active and advance period dates when a trialing subscription r [ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-04-08T00:00:00.000Z'), expirationDate: new Date('2026-04-08T00:00:00.000Z'), @@ -471,6 +477,7 @@ test('should remove or cancel the record and revoke entitlement when a trialing [ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-04-01T00:00:00.000Z'), expirationDate: new Date('2025-04-08T00:00:00.000Z'), @@ -483,6 +490,7 @@ test('should remove or cancel the record and revoke entitlement when a trialing [ { identifier: 'Pro', + isTrial: false, isActive: false, latestPurchaseDate: new Date('2025-04-01T00:00:00.000Z'), expirationDate: new Date('2024-01-01T00:00:00.000Z'), @@ -518,6 +526,7 @@ test('should set canceledAt and keep active until expiration when will_renew is mockSub([ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-05-01T00:00:00.000Z'), expirationDate: new Date('2025-06-01T00:00:00.000Z'), @@ -554,6 +563,7 @@ test('should retain record as past_due (inactive but not expired) and NOT emit c mockSub([ { identifier: 'Pro', + isTrial: false, isActive: false, latestPurchaseDate: new Date('2025-05-01T00:00:00.000Z'), expirationDate: new Date('2999-01-01T00:00:00.000Z'), @@ -657,6 +667,7 @@ test('should skip RC upsert when Stripe active already exists for same plan', as mockSub([ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-06-01T00:00:00.000Z'), expirationDate: new Date('2025-07-01T00:00:00.000Z'), @@ -722,6 +733,7 @@ test('should reconcile and fix missing or out-of-order states for revenuecat Act const subscriber = mockSub([ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-03-01T00:00:00.000Z'), expirationDate: new Date('2026-03-01T00:00:00.000Z'), @@ -759,6 +771,7 @@ test('should treat refund as early expiration and revoke immediately', async t = mockSub([ { identifier: 'Pro', + isTrial: false, isActive: false, latestPurchaseDate: new Date('2025-01-01T00:00:00.000Z'), expirationDate: new Date('2025-01-15T00:00:00.000Z'), @@ -790,6 +803,7 @@ test('should ignore non-whitelisted productId and not write to DB', async t => { mockSub([ { identifier: 'Weird', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-07-01T00:00:00.000Z'), expirationDate: new Date('2026-07-01T00:00:00.000Z'), @@ -819,6 +833,7 @@ test('should map via entitlement+duration when productId not whitelisted (P1M/P1 [ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-08-01T00:00:00.000Z'), expirationDate: new Date('2025-09-01T00:00:00.000Z'), @@ -831,6 +846,7 @@ test('should map via entitlement+duration when productId not whitelisted (P1M/P1 [ { identifier: 'AI', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-10-01T00:00:00.000Z'), expirationDate: new Date('2026-10-01T00:00:00.000Z'), @@ -843,6 +859,7 @@ test('should map via entitlement+duration when productId not whitelisted (P1M/P1 [ { identifier: 'Pro', + isTrial: false, isActive: true, latestPurchaseDate: new Date('2025-11-01T00:00:00.000Z'), expirationDate: new Date('2026-02-01T00:00:00.000Z'), diff --git a/packages/backend/server/src/plugins/payment/revenuecat/controller.ts b/packages/backend/server/src/plugins/payment/revenuecat/controller.ts index 27246e67fe..6c60b84d56 100644 --- a/packages/backend/server/src/plugins/payment/revenuecat/controller.ts +++ b/packages/backend/server/src/plugins/payment/revenuecat/controller.ts @@ -30,11 +30,14 @@ const RcEventSchema = z app_user_id: z.string().optional(), store: z.string().optional(), - is_family_share: z.boolean().optional(), - period_type: z.string().optional(), - original_transaction_id: z.string().optional(), - transaction_id: z.string().optional(), - purchase_token: z.string().optional(), + is_family_share: z.boolean().nullable().optional(), + period_type: z + .enum(['TRIAL', 'INTRO', 'NORMAL', 'PROMOTIONAL', 'PREPAID']) + .nullable() + .optional(), + original_transaction_id: z.string().nullable().optional(), + transaction_id: z.string().nullable().optional(), + purchase_token: z.string().nullable().optional(), }) .passthrough(); @@ -74,7 +77,11 @@ export class RevenueCatWebhookController { `[${id}] RevenueCat Webhook {${type}} received for appUserId=${appUserId}.` ); - if (appUserId && !event.is_family_share) { + if ( + appUserId && + (typeof event.is_family_share !== 'boolean' || + !event.is_family_share) + ) { // immediately ack and process asynchronously this.event .emitAsync('revenuecat.webhook', { appUserId, event }) diff --git a/packages/backend/server/src/plugins/payment/revenuecat/service.ts b/packages/backend/server/src/plugins/payment/revenuecat/service.ts index e3450eb292..e3da60fdd4 100644 --- a/packages/backend/server/src/plugins/payment/revenuecat/service.ts +++ b/packages/backend/server/src/plugins/payment/revenuecat/service.ts @@ -3,6 +3,18 @@ import { z } from 'zod'; import { Config } from '../../../base'; +const Store = z.enum([ + 'amazon', + 'app_store', + 'mac_app_store', + 'play_store', + 'promotional', + 'stripe', + 'rc_billing', + 'roku', + 'paddle', +]); + const zRcV2RawProduct = z .object({ id: z.string().nonempty(), @@ -11,20 +23,7 @@ const zRcV2RawProduct = z .object({ duration: z.string().nullable() }) .partial() .nullable(), - app: z - .object({ - type: z.enum([ - 'amazon', - 'app_store', - 'mac_app_store', - 'play_store', - 'stripe', - 'rc_billing', - 'roku', - 'paddle', - ]), - }) - .partial(), + app: z.object({ type: Store }).partial(), }) .passthrough(); @@ -49,7 +48,7 @@ const zRcV2RawSubscription = z entitlements: zRcV2RawEntitlements, starts_at: z.number(), current_period_ends_at: z.number().nullable(), - store: z.string(), + store: Store, auto_renewal_status: z.enum([ 'will_renew', 'will_not_renew', @@ -83,11 +82,12 @@ const zRcV2RawEnvelope = z // v2 minimal, simplified structure exposed to callers export const Subscription = z.object({ identifier: z.string(), + isTrial: z.boolean(), isActive: z.boolean(), latestPurchaseDate: z.date().nullable(), expirationDate: z.date().nullable(), productId: z.string(), - store: z.string(), + store: Store, willRenew: z.boolean(), duration: z.string().nullable(), }); @@ -145,6 +145,7 @@ export class RevenueCatService { } return { identifier: ent.lookup_key, + isTrial: sub.status === 'trialing', isActive: sub.gives_access === true || sub.status === 'active' || diff --git a/packages/backend/server/src/plugins/payment/revenuecat/webhook.ts b/packages/backend/server/src/plugins/payment/revenuecat/webhook.ts index f98bcd67ae..0aa066a71d 100644 --- a/packages/backend/server/src/plugins/payment/revenuecat/webhook.ts +++ b/packages/backend/server/src/plugins/payment/revenuecat/webhook.ts @@ -51,10 +51,8 @@ export class RevenueCatWebhookHandler { // ignore non-whitelisted and non-fallbackable products if (!mapping) continue; - const { status, deleteInstead, canceledAt, iapStore } = this.mapStatus( - sub, - event - ); + const { status, deleteInstead, canceledAt, iapStore } = + this.mapStatus(sub); const rcExternalRef = this.pickExternalRef(event); @@ -174,10 +172,7 @@ export class RevenueCatWebhookHandler { ); } - private mapStatus( - sub: Subscription, - event?: RcEvent - ): { + private mapStatus(sub: Subscription): { status: SubscriptionStatus; iapStore: IapStore | null; deleteInstead: boolean; @@ -185,29 +180,16 @@ export class RevenueCatWebhookHandler { } { const now = Date.now(); const exp = sub.expirationDate?.getTime(); - const periodType = (event?.period_type || '').toLowerCase(); - const eventType = (event?.type || '').toString().toLowerCase(); // Determine iap store and external reference for observability - const iapStore = this.mapIapStore(sub.store, event); - - // Refund/chargeback/revocation should be treated as immediate expiration - // Prioritize these event types regardless of current sub.isActive flag - if ( - eventType.includes('refund') || - eventType.includes('chargeback') || - eventType.includes('revocation') || - eventType.includes('revoke') - ) { - return { - iapStore, - status: SubscriptionStatus.Canceled, - deleteInstead: true, - }; - } + const iapStore = ['app_store', 'mac_app_store'].includes(sub.store) + ? IapStore.app_store + : ['play_store'].includes(sub.store) + ? IapStore.play_store + : null; if (sub.isActive) { - if (periodType === 'trial') { + if (sub.isTrial) { return { iapStore, status: SubscriptionStatus.Trialing, @@ -241,13 +223,4 @@ export class RevenueCatWebhookHandler { deleteInstead: true, }; } - - private mapIapStore(store?: string, event?: RcEvent): IapStore | null { - const s = (store || event?.store || '').toString().toLowerCase(); - if (!s) return null; - if (s.includes('app') || s.includes('ios')) return IapStore.app_store; - if (s.includes('play') || s.includes('android') || s.includes('google')) - return IapStore.play_store; - return null; - } } From 54498df2471a6fa02f19627226265060e2415c48 Mon Sep 17 00:00:00 2001 From: EYHN Date: Fri, 26 Sep 2025 14:27:45 +0800 Subject: [PATCH 26/28] feat(ios): upgrade button in setting (#13645) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary by CodeRabbit - New Features - Added a Subscription section in Mobile Settings (for signed-in users) with plan info and an Upgrade button that opens the native paywall. - Supports showing “Pro” and “AI” paywalls. - Integrated native paywall provider on iOS. - Style - Introduced new styling for the subscription card, content, and button. - Localization - Added English strings for subscription title, description, and button. - Chores - Minor iOS project cleanup and internal wiring to enable the paywall module. --- .../ios/App/App.xcodeproj/project.pbxproj | 6 +- packages/frontend/apps/ios/App/Podfile.lock | 12 ++-- packages/frontend/apps/ios/src/app.tsx | 7 +++ .../ios/src/plugins/paywall/definitions.ts | 2 +- .../core/src/mobile/dialogs/setting/index.tsx | 2 + .../dialogs/setting/subscription/index.tsx | 56 +++++++++++++++++++ .../setting/subscription/styles.css.ts | 37 ++++++++++++ packages/frontend/core/src/modules/index.ts | 2 + .../core/src/modules/paywall/index.ts | 10 ++++ .../paywall/providers/native-paywall.ts | 9 +++ .../paywall/services/native-paywall.ts | 13 +++++ .../i18n/src/i18n-completenesses.json | 2 +- packages/frontend/i18n/src/i18n.gen.ts | 12 ++++ packages/frontend/i18n/src/resources/en.json | 3 + 14 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 packages/frontend/core/src/mobile/dialogs/setting/subscription/index.tsx create mode 100644 packages/frontend/core/src/mobile/dialogs/setting/subscription/styles.css.ts create mode 100644 packages/frontend/core/src/modules/paywall/index.ts create mode 100644 packages/frontend/core/src/modules/paywall/providers/native-paywall.ts create mode 100644 packages/frontend/core/src/modules/paywall/services/native-paywall.ts diff --git a/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj b/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj index 451bb06829..92d8c25bc2 100644 --- a/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj +++ b/packages/frontend/apps/ios/App/App.xcodeproj/project.pbxproj @@ -88,6 +88,8 @@ /* Begin PBXFileSystemSynchronizedRootGroup section */ 9DAE85B72E7BAC3B00DB9F1D /* Plugins */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + ); path = Plugins; sourceTree = ""; }; @@ -307,13 +309,9 @@ ); inputFileListPaths = ( ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AFFiNE/Pods-AFFiNE-frameworks.sh\"\n"; diff --git a/packages/frontend/apps/ios/App/Podfile.lock b/packages/frontend/apps/ios/App/Podfile.lock index ef43285496..87d06e4df2 100644 --- a/packages/frontend/apps/ios/App/Podfile.lock +++ b/packages/frontend/apps/ios/App/Podfile.lock @@ -45,13 +45,13 @@ EXTERNAL SOURCES: :path: "../../../../../node_modules/capacitor-plugin-app-tracking-transparency" SPEC CHECKSUMS: - Capacitor: 03bc7cbdde6a629a8b910a9d7d78c3cc7ed09ea7 - CapacitorApp: febecbb9582cb353aed037e18ec765141f880fe9 - CapacitorBrowser: 6299776d496e968505464884d565992faa20444a + Capacitor: 106e7a4205f4618d582b886a975657c61179138d + CapacitorApp: d63334c052278caf5d81585d80b21905c6f93f39 + CapacitorBrowser: 081852cf532acf77b9d2953f3a88fe5b9711fb06 CapacitorCordova: 5967b9ba03915ef1d585469d6e31f31dc49be96f - CapacitorHaptics: 1f1e17041f435d8ead9ff2a34edd592c6aa6a8d6 - CapacitorKeyboard: 09fd91dcde4f8a37313e7f11bde553ad1ed52036 - CapacitorPluginAppTrackingTransparency: 92ae9c1cfb5cf477753db9269689332a686f675a + CapacitorHaptics: 70e47470fa1a6bd6338cd102552e3846b7f9a1b3 + CapacitorKeyboard: 969647d0ca2e5c737d7300088e2517aa832434e2 + CapacitorPluginAppTrackingTransparency: 2a2792623a5a72795f2e8f9ab3f1147573732fd8 CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483 PODFILE CHECKSUM: 2c1e4be82121f2d9724ecf7e31dd14e165aeb082 diff --git a/packages/frontend/apps/ios/src/app.tsx b/packages/frontend/apps/ios/src/app.tsx index bb8bd6f2a5..825404201d 100644 --- a/packages/frontend/apps/ios/src/app.tsx +++ b/packages/frontend/apps/ios/src/app.tsx @@ -21,6 +21,7 @@ import { FeatureFlagService } from '@affine/core/modules/feature-flag'; import { GlobalContextService } from '@affine/core/modules/global-context'; import { I18nProvider } from '@affine/core/modules/i18n'; import { LifecycleService } from '@affine/core/modules/lifecycle'; +import { NativePaywallProvider } from '@affine/core/modules/paywall'; import { configureLocalStorageStateStorageImpls, NbstoreProvider, @@ -63,6 +64,7 @@ import { ModalConfigProvider } from './modal-config'; import { Auth } from './plugins/auth'; import { Hashcash } from './plugins/hashcash'; import { NbStoreNativeDBApis } from './plugins/nbstore'; +import { PayWall } from './plugins/paywall'; import { writeEndpointToken } from './proxy'; import { enableNavigationGesture$ } from './web-navigation-control'; @@ -198,6 +200,11 @@ framework.scope(ServerScope).override(AuthProvider, resolver => { }, }; }); +framework.impl(NativePaywallProvider, { + showPaywall: async (type: 'Pro' | 'AI') => { + await PayWall.showPayWall({ type }); + }, +}); const frameworkProvider = framework.provider(); diff --git a/packages/frontend/apps/ios/src/plugins/paywall/definitions.ts b/packages/frontend/apps/ios/src/plugins/paywall/definitions.ts index edc258657e..f57ddaf0db 100644 --- a/packages/frontend/apps/ios/src/plugins/paywall/definitions.ts +++ b/packages/frontend/apps/ios/src/plugins/paywall/definitions.ts @@ -1,5 +1,5 @@ export interface PayWallPlugin { showPayWall(options: { - type: string; + type: 'Pro' | 'AI'; }): Promise<{ success: boolean; type: string }>; } diff --git a/packages/frontend/core/src/mobile/dialogs/setting/index.tsx b/packages/frontend/core/src/mobile/dialogs/setting/index.tsx index 410c94571c..4db02b137c 100644 --- a/packages/frontend/core/src/mobile/dialogs/setting/index.tsx +++ b/packages/frontend/core/src/mobile/dialogs/setting/index.tsx @@ -12,6 +12,7 @@ import { AppearanceGroup } from './appearance'; import { ExperimentalFeatureSetting } from './experimental'; import { OthersGroup } from './others'; import * as styles from './style.css'; +import { UserSubscription } from './subscription'; import { SwipeDialog } from './swipe-dialog'; import { UserProfile } from './user-profile'; import { UserUsage } from './user-usage'; @@ -23,6 +24,7 @@ const MobileSetting = () => { return (
+ diff --git a/packages/frontend/core/src/mobile/dialogs/setting/subscription/index.tsx b/packages/frontend/core/src/mobile/dialogs/setting/subscription/index.tsx new file mode 100644 index 0000000000..e9b46b98a4 --- /dev/null +++ b/packages/frontend/core/src/mobile/dialogs/setting/subscription/index.tsx @@ -0,0 +1,56 @@ +import { Button } from '@affine/component'; +import { AuthService, ServerService } from '@affine/core/modules/cloud'; +import { NativePaywallService } from '@affine/core/modules/paywall'; +import { useI18n } from '@affine/i18n'; +import { useLiveData, useService } from '@toeverything/infra'; + +import * as styles from './styles.css'; + +export const UserSubscription = () => { + const serverService = useService(ServerService); + const authService = useService(AuthService); + const nativePaywallProvider = + useService(NativePaywallService).getNativePaywallProvider(); + const t = useI18n(); + + const supported = useLiveData( + serverService.server.features$.map(f => f.payment) + ); + + const loggedIn = useLiveData(authService.session.status$) === 'authenticated'; + + if (!loggedIn) { + return null; + } + + if (!supported) { + // TODO: enable this + // return null; + } + + if (!nativePaywallProvider) { + return null; + } + + return ( +
+
+
+ {t['com.affine.payment.subscription.title']()} +
+
+ {t['com.affine.payment.subscription.description']()} +
+
+ +
+ ); +}; diff --git a/packages/frontend/core/src/mobile/dialogs/setting/subscription/styles.css.ts b/packages/frontend/core/src/mobile/dialogs/setting/subscription/styles.css.ts new file mode 100644 index 0000000000..f18bab4f59 --- /dev/null +++ b/packages/frontend/core/src/mobile/dialogs/setting/subscription/styles.css.ts @@ -0,0 +1,37 @@ +import { cssVarV2 } from '@toeverything/theme/v2'; +import { style } from '@vanilla-extract/css'; + +export const root = style({ + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + gap: 16, + border: `1px solid ${cssVarV2('database/border')}`, + borderRadius: '12px', + padding: '10px 16px', + backgroundColor: cssVarV2('edgeless/selection/selectionMarqueeBackground'), +}); + +export const content = style({ + display: 'flex', + flexDirection: 'column', + gap: 4, +}); + +export const title = style({ + fontSize: '17px', + lineHeight: '22px', + fontWeight: 600, + color: cssVarV2('text/primary'), +}); + +export const description = style({ + fontSize: '13px', + lineHeight: '18px', + fontWeight: 400, + color: cssVarV2('text/secondary'), +}); + +export const button = style({ + fontSize: '15px', +}); diff --git a/packages/frontend/core/src/modules/index.ts b/packages/frontend/core/src/modules/index.ts index 49079723af..c09aa994ee 100644 --- a/packages/frontend/core/src/modules/index.ts +++ b/packages/frontend/core/src/modules/index.ts @@ -44,6 +44,7 @@ import { configureNavigationPanelModule } from './navigation-panel'; import { configureNotificationModule } from './notification'; import { configureOpenInApp } from './open-in-app'; import { configureOrganizeModule } from './organize'; +import { configurePaywallModule } from './paywall'; import { configurePDFModule } from './pdf'; import { configurePeekViewModule } from './peek-view'; import { configurePermissionsModule } from './permissions'; @@ -130,4 +131,5 @@ export function configureCommonModules(framework: Framework) { configureIndexerEmbeddingModule(framework); configureCommentModule(framework); configureDocSummaryModule(framework); + configurePaywallModule(framework); } diff --git a/packages/frontend/core/src/modules/paywall/index.ts b/packages/frontend/core/src/modules/paywall/index.ts new file mode 100644 index 0000000000..785e81cffe --- /dev/null +++ b/packages/frontend/core/src/modules/paywall/index.ts @@ -0,0 +1,10 @@ +import type { Framework } from '@toeverything/infra'; + +import { NativePaywallService } from './services/native-paywall'; + +export { NativePaywallProvider } from './providers/native-paywall'; +export { NativePaywallService } from './services/native-paywall'; + +export function configurePaywallModule(framework: Framework) { + framework.service(NativePaywallService); +} diff --git a/packages/frontend/core/src/modules/paywall/providers/native-paywall.ts b/packages/frontend/core/src/modules/paywall/providers/native-paywall.ts new file mode 100644 index 0000000000..b8a1ad066b --- /dev/null +++ b/packages/frontend/core/src/modules/paywall/providers/native-paywall.ts @@ -0,0 +1,9 @@ +import { createIdentifier } from '@toeverything/infra'; + +export interface NativePaywallProvider { + showPaywall(type: 'Pro' | 'AI'): Promise; +} + +export const NativePaywallProvider = createIdentifier( + 'NativePaywallProvider' +); diff --git a/packages/frontend/core/src/modules/paywall/services/native-paywall.ts b/packages/frontend/core/src/modules/paywall/services/native-paywall.ts new file mode 100644 index 0000000000..418a3dbdf6 --- /dev/null +++ b/packages/frontend/core/src/modules/paywall/services/native-paywall.ts @@ -0,0 +1,13 @@ +import { Service } from '@toeverything/infra'; + +import { NativePaywallProvider } from '../providers/native-paywall'; + +export class NativePaywallService extends Service { + constructor() { + super(); + } + + getNativePaywallProvider() { + return this.framework.getOptional(NativePaywallProvider); + } +} diff --git a/packages/frontend/i18n/src/i18n-completenesses.json b/packages/frontend/i18n/src/i18n-completenesses.json index 88fc0ffc18..1ff79f6d80 100644 --- a/packages/frontend/i18n/src/i18n-completenesses.json +++ b/packages/frontend/i18n/src/i18n-completenesses.json @@ -14,7 +14,7 @@ "it-IT": 100, "it": 1, "ja": 100, - "ko": 53, + "ko": 52, "pl": 100, "pt-BR": 100, "ru": 100, diff --git a/packages/frontend/i18n/src/i18n.gen.ts b/packages/frontend/i18n/src/i18n.gen.ts index d9dbd536c9..52539d1265 100644 --- a/packages/frontend/i18n/src/i18n.gen.ts +++ b/packages/frontend/i18n/src/i18n.gen.ts @@ -8306,6 +8306,18 @@ export function useAFFiNEI18N(): { * `Only current mode` */ ["com.affine.comment.filter.only-current-mode"](): string; + /** + * `Unlock more features` + */ + ["com.affine.payment.subscription.title"](): string; + /** + * `The universal editor that lets you work, play, present or create just about anything.` + */ + ["com.affine.payment.subscription.description"](): string; + /** + * `Upgrade` + */ + ["com.affine.payment.subscription.button"](): string; /** * `Reply` */ diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index a50e399622..46689d1a6a 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -2084,6 +2084,9 @@ "com.affine.comment.filter.show-resolved": "Show resolved comments", "com.affine.comment.filter.only-my-replies": "Only my replies and mentions", "com.affine.comment.filter.only-current-mode": "Only current mode", + "com.affine.payment.subscription.title": "Unlock more features", + "com.affine.payment.subscription.description": "The universal editor that lets you work, play, present or create just about anything.", + "com.affine.payment.subscription.button": "Upgrade", "com.affine.comment.reply": "Reply", "com.affine.comment.copy-link": "Copy link", "com.affine.context-menu.copy": "Copy", From c5404004965cc8787f54950a43bc1e7f21a57ee4 Mon Sep 17 00:00:00 2001 From: DarkSky <25152247+darkskygit@users.noreply.github.com> Date: Fri, 26 Sep 2025 14:38:13 +0800 Subject: [PATCH 27/28] feat(server): allow drop session (#13650) ## Summary by CodeRabbit * **Bug Fixes** * Ensures deleted sessions and their messages are consistently cleaned up, preventing lingering pinned or partially removed items. * **Refactor** * Streamlined session cleanup into a single bulk operation for improved reliability and performance during deletions. --- .../server/src/models/copilot-session.ts | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/backend/server/src/models/copilot-session.ts b/packages/backend/server/src/models/copilot-session.ts index 7912e5373d..4c2e8db9de 100644 --- a/packages/backend/server/src/models/copilot-session.ts +++ b/packages/backend/server/src/models/copilot-session.ts @@ -459,27 +459,19 @@ export class CopilotSessionModel extends BaseModel { docId: options.docId, deletedAt: null, }, - select: { id: true, prompt: true }, + select: { id: true }, }); + const sessionIds = sessions.map(({ id }) => id); // cleanup all messages await this.db.aiSessionMessage.deleteMany({ where: { sessionId: { in: sessionIds } }, }); - // only mark action session as deleted - // chat session always can be reuse - const actionIds = sessions - .filter(({ prompt }) => !!prompt.action) - .map(({ id }) => id); - - // 标记 action session 为已删除 - if (actionIds.length > 0) { - await this.db.aiSession.updateMany({ - where: { id: { in: actionIds } }, - data: { pinned: false, deletedAt: new Date() }, - }); - } + await this.db.aiSession.updateMany({ + where: { id: { in: sessionIds } }, + data: { pinned: false, deletedAt: new Date() }, + }); return sessionIds; } From d272c4342d6afe23d0d605de8264fb96783b262d Mon Sep 17 00:00:00 2001 From: Cats Juice Date: Fri, 26 Sep 2025 14:41:29 +0800 Subject: [PATCH 28/28] feat(core): replace emoji-mart with affine icon picker (#13644) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary by CodeRabbit - New Features - Unified icon picker with consistent rendering across the app. - Picker can auto-close after selection. - “Remove” now clears the icon selection. - Refactor - Icon handling consolidated across editors, navigation, and document titles for consistent behavior. - Picker now opens on the Emoji panel by default. - Style - Adjusted line-height and selectors for icon picker visuals. - Chores - Removed unused emoji-mart dependencies. --- packages/frontend/component/package.json | 2 - .../icon-name-editor/icon-name-editor.css.ts | 1 + .../icon-name-editor.stories.tsx | 14 ++-- .../ui/icon-name-editor/icon-name-editor.tsx | 79 +++++-------------- .../src/ui/icon-picker/icon-picker.tsx | 29 ++++--- .../component/src/ui/icon-picker/index.ts | 2 + .../component/src/ui/icon-picker/renderer.tsx | 31 +++++--- .../component/src/ui/icon-picker/type.ts | 20 +++++ .../block-suite-editor/doc-icon-picker.css.ts | 2 +- .../block-suite-editor/doc-icon-picker.tsx | 15 ++-- .../components/navigation-panel/tree/node.tsx | 16 ++-- .../core/src/modules/db/schema/schema.ts | 8 +- .../services/doc-display-meta.ts | 7 +- .../doc-display-meta/services/icon.tsx | 7 ++ .../explorer-icon/store/explorer-icon.ts | 14 +--- yarn.lock | 12 --- 16 files changed, 121 insertions(+), 138 deletions(-) create mode 100644 packages/frontend/component/src/ui/icon-picker/type.ts create mode 100644 packages/frontend/core/src/modules/doc-display-meta/services/icon.tsx diff --git a/packages/frontend/component/package.json b/packages/frontend/component/package.json index c9e9efd997..744746c480 100644 --- a/packages/frontend/component/package.json +++ b/packages/frontend/component/package.json @@ -28,8 +28,6 @@ "@atlaskit/pragmatic-drag-and-drop": "^1.4.0", "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3", "@blocksuite/icons": "^2.2.17", - "@emoji-mart/data": "^1.2.1", - "@emoji-mart/react": "^1.1.1", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@radix-ui/react-avatar": "^1.1.2", diff --git a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts index 01431acbca..89aa208ad0 100644 --- a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts +++ b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts @@ -15,6 +15,7 @@ export const contentRoot = style({ export const iconPicker = style({ padding: 0, + lineHeight: 1, }); globalStyle(`${iconPicker} span:has(svg)`, { lineHeight: 0, diff --git a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx index 56f2f696f4..c63a8bda65 100644 --- a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx +++ b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx @@ -2,12 +2,12 @@ import type { Meta, StoryFn } from '@storybook/react'; import { useCallback, useState } from 'react'; import { Button } from '../button'; +import { type IconData, IconType } from '../icon-picker'; import { ResizePanel } from '../resize-panel/resize-panel'; import { IconAndNameEditorMenu, type IconAndNameEditorMenuProps, IconEditor, - type IconType, } from './icon-name-editor'; export default { @@ -16,10 +16,13 @@ export default { } satisfies Meta; export const Basic: StoryFn = () => { - const [icon, setIcon] = useState('👋'); + const [icon, setIcon] = useState({ + type: IconType.Emoji, + unicode: '👋', + }); const [name, setName] = useState('Hello'); - const handleIconChange = useCallback((_?: IconType, icon?: string) => { + const handleIconChange = useCallback((icon?: IconData) => { setIcon(icon); }, []); const handleNameChange = useCallback((name: string) => { @@ -28,7 +31,7 @@ export const Basic: StoryFn = () => { return (
-

Icon: {icon}

+

Icon: {JSON.stringify(icon)}

Name: {name}

= () => { }} > void; + onIconChange?: (data?: IconData) => void; triggerClassName?: string; } @@ -38,25 +34,7 @@ export interface IconAndNameEditorMenuProps skipIfNotChanged?: boolean; } -export const IconRenderer = ({ - iconType, - icon, - fallback, -}: { - iconType: IconType; - icon: string; - fallback?: ReactNode; -}) => { - switch (iconType) { - case 'emoji': - return
{icon ?? fallback}
; - default: - return
{fallback}
; - } -}; - export const IconEditor = ({ - iconType, icon, closeAfterSelect, iconPlaceholder, @@ -71,16 +49,17 @@ export const IconEditor = ({ triggerVariant?: ButtonProps['variant']; }) => { const [isPickerOpen, setIsPickerOpen] = useState(false); - const { resolvedTheme } = useTheme(); - const handleEmojiClick = useCallback( - (emoji: any) => { - onIconChange?.('emoji', emoji.native); + + const handleSelect = useCallback( + (data?: IconData) => { + onIconChange?.(data); if (closeAfterSelect) { setIsPickerOpen(false); } }, [closeAfterSelect, onIconChange] ); + return ( e.stopPropagation()}> - +
} > ); @@ -160,7 +127,6 @@ export const IconAndNameEditorMenu = ({ open, onOpenChange, width = 300, - iconType: initialIconType, icon: initialIcon, name: initialName, onIconChange, @@ -169,15 +135,15 @@ export const IconAndNameEditorMenu = ({ iconPlaceholder, skipIfNotChanged = true, inputTestId, + closeAfterSelect, ...menuProps }: IconAndNameEditorMenuProps) => { - const [iconType, setIconType] = useState(initialIconType); const [icon, setIcon] = useState(initialIcon); const [name, setName] = useState(initialName); const commit = useCallback(() => { - if (iconType !== initialIconType || icon !== initialIcon) { - onIconChange?.(iconType, icon); + if (icon !== initialIcon) { + onIconChange?.(icon); } if (skipIfNotChanged) { if (name !== initialName) onNameChange?.(name); @@ -186,9 +152,7 @@ export const IconAndNameEditorMenu = ({ } }, [ icon, - iconType, initialIcon, - initialIconType, initialName, name, onIconChange, @@ -196,13 +160,11 @@ export const IconAndNameEditorMenu = ({ skipIfNotChanged, ]); const abort = useCallback(() => { - setIconType(initialIconType); setIcon(initialIcon); setName(initialName); - }, [initialIcon, initialIconType, initialName]); - const handleIconChange = useCallback((type?: IconType, icon?: string) => { - setIconType(type); - setIcon(icon); + }, [initialIcon, initialName]); + const handleIconChange = useCallback((data?: IconData) => { + setIcon(data); }, []); const handleNameChange = useCallback((name: string) => { setName(name); @@ -210,13 +172,12 @@ export const IconAndNameEditorMenu = ({ const handleMenuOpenChange = useCallback( (open: boolean) => { if (open) { - setIconType(initialIconType); setIcon(initialIcon); setName(initialName); } onOpenChange?.(open); }, - [initialIcon, initialIconType, initialName, onOpenChange] + [initialIcon, initialName, onOpenChange] ); return ( @@ -243,10 +204,10 @@ export const IconAndNameEditorMenu = ({ {...menuProps} items={ = [ { value: 'Emoji', className: styles.headerNavItem }, @@ -16,17 +17,11 @@ const panels: Array = [ export const IconPicker = ({ className, style, -}: HTMLAttributes & { - onSelect?: ( - type: 'emoji' | 'affine-icon', - data: { icon?: string; color?: string } - ) => void; + onSelect, +}: Omit, 'onSelect'> & { + onSelect?: (data?: IconData) => void; }) => { - const [activePanel, setActivePanel] = useState('Icons'); - - // const ActivePanel = panels.find( - // panel => panel.value === activePanel - // )?.component; + const [activePanel, setActivePanel] = useState('Emoji'); return (
@@ -53,7 +48,7 @@ export const IconPicker = ({ @@ -61,9 +56,17 @@ export const IconPicker = ({
{activePanel === 'Emoji' ? ( - + { + onSelect?.({ type: IconType.Emoji, unicode: emoji }); + }} + /> ) : activePanel === 'Icons' ? ( - + { + onSelect?.({ type: IconType.AffineIcon, name: icon, color }); + }} + /> ) : null}
diff --git a/packages/frontend/component/src/ui/icon-picker/index.ts b/packages/frontend/component/src/ui/icon-picker/index.ts index 1fd5d61e59..d4da1beb36 100644 --- a/packages/frontend/component/src/ui/icon-picker/index.ts +++ b/packages/frontend/component/src/ui/icon-picker/index.ts @@ -1 +1,3 @@ export * from './icon-picker'; +export * from './renderer'; +export * from './type'; diff --git a/packages/frontend/component/src/ui/icon-picker/renderer.tsx b/packages/frontend/component/src/ui/icon-picker/renderer.tsx index f8a93cc23d..3410798565 100644 --- a/packages/frontend/component/src/ui/icon-picker/renderer.tsx +++ b/packages/frontend/component/src/ui/icon-picker/renderer.tsx @@ -1,18 +1,29 @@ +import type { ReactNode } from 'react'; + import { AffineIconRenderer } from './renderer/affine-icon'; +import { type IconData, IconType } from './type'; export const IconRenderer = ({ - iconType, - icon, + data, + fallback, }: { - iconType: 'emoji' | 'affine-icon'; - icon: string; + data?: IconData; + fallback?: ReactNode; }) => { - if (iconType === 'emoji') { - return icon; - } - if (iconType === 'affine-icon') { - return ; + if (!data) { + return fallback ?? null; } - return null; + if (data.type === IconType.Emoji && data.unicode) { + return data.unicode; + } + if (data.type === IconType.AffineIcon && data.name) { + return ; + } + if (data.type === IconType.Blob) { + // Not supported yet + return null; + } + + return fallback ?? null; }; diff --git a/packages/frontend/component/src/ui/icon-picker/type.ts b/packages/frontend/component/src/ui/icon-picker/type.ts new file mode 100644 index 0000000000..ba089983a7 --- /dev/null +++ b/packages/frontend/component/src/ui/icon-picker/type.ts @@ -0,0 +1,20 @@ +export enum IconType { + Emoji = 'emoji', + AffineIcon = 'affine-icon', + Blob = 'blob', +} + +export type IconData = + | { + type: IconType.Emoji; + unicode: string; + } + | { + type: IconType.AffineIcon; + name: string; + color: string; + } + | { + type: IconType.Blob; + blob: Blob; + }; diff --git a/packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.css.ts b/packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.css.ts index 3edfb9695a..6711032de6 100644 --- a/packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.css.ts +++ b/packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.css.ts @@ -6,7 +6,7 @@ export const docIconPickerTrigger = style({ height: 64, padding: 2, selectors: { - '&[data-icon-type="emoji"]': { + '&[data-icon-type="emoji"], &[data-icon-type="affine-icon"]': { fontSize: 60, lineHeight: 1, }, diff --git a/packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.tsx b/packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.tsx index 97da80543f..4ced934af2 100644 --- a/packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.tsx +++ b/packages/frontend/core/src/blocksuite/block-suite-editor/doc-icon-picker.tsx @@ -40,12 +40,15 @@ export const DocIconPicker = ({ const icon = useLiveData(explorerIconService.icon$('doc', docId)); - const isPlaceholder = !icon?.type || !icon?.icon; + const isPlaceholder = !icon?.icon; if (readonly) { return isPlaceholder ? null : ( -
- +
+
); } @@ -53,14 +56,12 @@ export const DocIconPicker = ({ return ( { + onIconChange={data => { explorerIconService.setIcon({ where: 'doc', id: docId, - type, - icon, + icon: data, }); }} closeAfterSelect={true} diff --git a/packages/frontend/core/src/desktop/components/navigation-panel/tree/node.tsx b/packages/frontend/core/src/desktop/components/navigation-panel/tree/node.tsx index c3ee0adb57..299bfcc828 100644 --- a/packages/frontend/core/src/desktop/components/navigation-panel/tree/node.tsx +++ b/packages/frontend/core/src/desktop/components/navigation-panel/tree/node.tsx @@ -6,6 +6,8 @@ import { type DropTargetTreeInstruction, IconAndNameEditorMenu, IconButton, + type IconData, + IconRenderer, Menu, MenuItem, useDraggable, @@ -13,7 +15,6 @@ import { } from '@affine/component'; import { Guard } from '@affine/core/components/guard'; import { AppSidebarService } from '@affine/core/modules/app-sidebar'; -import type { ExplorerIconType } from '@affine/core/modules/db/schema/schema'; import { ExplorerIconService } from '@affine/core/modules/explorer-icon/services/explorer-icon'; import type { ExplorerType } from '@affine/core/modules/explorer-icon/store/explorer-icon'; import type { DocPermissionActions } from '@affine/core/modules/permissions'; @@ -142,13 +143,12 @@ export const NavigationPanelTreeNodeRenameModal = ({ ); const onIconChange = useCallback( - (type?: ExplorerIconType, icon?: string) => { + (data?: IconData) => { if (!explorerIconConfig) return; explorerIconService.setIcon({ where: explorerIconConfig.where, id: explorerIconConfig.id, - type, - icon, + icon: data, }); }, [explorerIconConfig, explorerIconService] @@ -161,8 +161,7 @@ export const NavigationPanelTreeNodeRenameModal = ({ onIconChange={onIconChange} onNameChange={handleRename} name={rawName ?? ''} - iconType={explorerIcon?.type ?? 'emoji'} - icon={explorerIcon?.icon ?? ''} + icon={explorerIcon?.icon} width={sidebarWidth - 16} contentOptions={{ sideOffset: 36, @@ -461,10 +460,7 @@ export const NavigationPanelTreeNode = ({ />
- {/* Only emoji icon is supported for now */} - {explorerIcon && explorerIcon.type === 'emoji' - ? explorerIcon.icon - : fallbackIcon} +
diff --git a/packages/frontend/core/src/modules/db/schema/schema.ts b/packages/frontend/core/src/modules/db/schema/schema.ts index 44fb5246ad..eff152b2cb 100644 --- a/packages/frontend/core/src/modules/db/schema/schema.ts +++ b/packages/frontend/core/src/modules/db/schema/schema.ts @@ -1,3 +1,4 @@ +import type { IconData } from '@affine/component'; import { type DBSchemaBuilder, f, @@ -51,8 +52,7 @@ export const AFFiNE_WORKSPACE_DB_SCHEMA = { * ${doc|collection|folder|tag}:${id} */ id: f.string().primaryKey(), - type: f.enum('emoji', 'affine-icon', 'blob'), - icon: f.string(), + icon: f.json(), }, } as const satisfies DBSchemaBuilder; export type AFFiNEWorkspaceDbSchema = typeof AFFiNE_WORKSPACE_DB_SCHEMA; @@ -61,10 +61,6 @@ export type DocProperties = ORMEntity; export type DocCustomPropertyInfo = ORMEntity< AFFiNEWorkspaceDbSchema['docCustomPropertyInfo'] >; -export type ExplorerIcon = ORMEntity; -export type ExplorerIconType = ORMEntity< - AFFiNEWorkspaceDbSchema['explorerIcon'] ->['type']; export const AFFiNE_WORKSPACE_USERDATA_DB_SCHEMA = { favorite: { diff --git a/packages/frontend/core/src/modules/doc-display-meta/services/doc-display-meta.ts b/packages/frontend/core/src/modules/doc-display-meta/services/doc-display-meta.ts index 8a70874a63..f0fca2a56a 100644 --- a/packages/frontend/core/src/modules/doc-display-meta/services/doc-display-meta.ts +++ b/packages/frontend/core/src/modules/doc-display-meta/services/doc-display-meta.ts @@ -29,6 +29,7 @@ import type { DocRecord, DocsService } from '../../doc'; import type { ExplorerIconService } from '../../explorer-icon/services/explorer-icon'; import type { I18nService } from '../../i18n'; import type { JournalService } from '../../journal'; +import { getDocIconComponent } from './icon'; type IconType = 'rc' | 'lit'; interface DocDisplayIconOptions { @@ -149,8 +150,10 @@ export class DocDisplayMetaService extends Service { if (enableEmojiIcon) { // const { emoji } = extractEmojiIcon(title); // if (emoji) return () => emoji; - const icon = get(this.explorerIconService.icon$('doc', docId)); - if (icon && icon.type === 'emoji') return () => icon.icon; + const icon = get(this.explorerIconService.icon$('doc', docId))?.icon; + if (icon) { + return getDocIconComponent(icon); + } } // title alias diff --git a/packages/frontend/core/src/modules/doc-display-meta/services/icon.tsx b/packages/frontend/core/src/modules/doc-display-meta/services/icon.tsx new file mode 100644 index 0000000000..f65367056e --- /dev/null +++ b/packages/frontend/core/src/modules/doc-display-meta/services/icon.tsx @@ -0,0 +1,7 @@ +import { type IconData, IconRenderer } from '@affine/component'; + +export const getDocIconComponent = (icon: IconData) => { + const Icon = () => ; + Icon.displayName = 'DocIcon'; + return Icon; +}; diff --git a/packages/frontend/core/src/modules/explorer-icon/store/explorer-icon.ts b/packages/frontend/core/src/modules/explorer-icon/store/explorer-icon.ts index fd5619ef59..db46883924 100644 --- a/packages/frontend/core/src/modules/explorer-icon/store/explorer-icon.ts +++ b/packages/frontend/core/src/modules/explorer-icon/store/explorer-icon.ts @@ -1,7 +1,7 @@ +import type { IconData } from '@affine/component'; import { Store } from '@toeverything/infra'; import type { WorkspaceDBService } from '../../db'; -import type { ExplorerIconType } from '../../db/schema/schema'; export type ExplorerType = 'doc' | 'collection' | 'folder' | 'tag'; @@ -18,21 +18,15 @@ export class ExplorerIconStore extends Store { return this.dbService.db.explorerIcon.get(`${type}:${id}`); } - setIcon(options: { - where: ExplorerType; - id: string; - type?: ExplorerIconType; - icon?: string; - }) { - const { where, id, type, icon } = options; + setIcon(options: { where: ExplorerType; id: string; icon?: IconData }) { + const { where, id, icon } = options; // remove icon - if (!type || !icon) { + if (!icon) { return this.dbService.db.explorerIcon.delete(`${where}:${id}`); } // upsert icon return this.dbService.db.explorerIcon.create({ id: `${where}:${id}`, - type, icon, }); } diff --git a/yarn.lock b/yarn.lock index dbeb6a867a..e57230b70c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -314,8 +314,6 @@ __metadata: "@blocksuite/affine": "workspace:*" "@blocksuite/icons": "npm:^2.2.17" "@chromatic-com/storybook": "npm:^4.0.0" - "@emoji-mart/data": "npm:^1.2.1" - "@emoji-mart/react": "npm:^1.1.1" "@emotion/react": "npm:^11.14.0" "@emotion/styled": "npm:^11.14.0" "@radix-ui/react-avatar": "npm:^1.1.2" @@ -5532,16 +5530,6 @@ __metadata: languageName: node linkType: hard -"@emoji-mart/react@npm:^1.1.1": - version: 1.1.1 - resolution: "@emoji-mart/react@npm:1.1.1" - peerDependencies: - emoji-mart: ^5.2 - react: ^16.8 || ^17 || ^18 - checksum: 10/def4dddaa01ce88c396510d84d1878b881fe0f9c484a836a50e3db784a91ab98edf94816cff503b4d1cab7b00400a01c87e32d19dee2d950f64ef9243f79101e - languageName: node - linkType: hard - "@emotion/babel-plugin@npm:^11.13.5": version: 11.13.5 resolution: "@emotion/babel-plugin@npm:11.13.5"