diff --git a/CHANGELOG.md b/CHANGELOG.md
index a512047819..4f7389c31c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -177,6 +177,7 @@
### Client
- Enhance: TLの返信表示オプションを記憶するように
- Enhance: 投稿されてから時間が経過しているノートであることを視覚的に分かりやすく
+- Feat: 絵文字ピッカーのカテゴリに「/」を入れることでフォルダ分け表示できるように
### Server
- Enhance: タイムライン取得時のパフォーマンスを向上
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 402c2413f8..a8f54e2e18 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -314,6 +314,7 @@ export interface Locale {
"createFolder": string;
"renameFolder": string;
"deleteFolder": string;
+ "folder": string;
"addFile": string;
"emptyDrive": string;
"emptyFolder": string;
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 2b2f05aa88..04fb1f947d 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -311,6 +311,7 @@ folderName: "フォルダー名"
createFolder: "フォルダーを作成"
renameFolder: "フォルダー名を変更"
deleteFolder: "フォルダーを削除"
+folder: "フォルダー"
addFile: "ファイルを追加"
emptyDrive: "ドライブは空です"
emptyFolder: "フォルダーは空です"
diff --git a/packages/frontend/src/components/MkEmojiPicker.section.vue b/packages/frontend/src/components/MkEmojiPicker.section.vue
index 08297ea5ba..35de9bbb5e 100644
--- a/packages/frontend/src/components/MkEmojiPicker.section.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.section.vue
@@ -5,9 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
+
- ({{ emojis.length }})
+ (:{{ emojis.length }})
+
+
+
+ (:{{ customEmojiTree.length }} :{{ emojis.length }})
+
+
+
+ {{ child.value || i18n.ts.other }}
+
+
+
+
+
+
diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue
index 5b420c499e..603f676d5d 100644
--- a/packages/frontend/src/components/MkEmojiPicker.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.vue
@@ -73,18 +73,20 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.customEmojis }}
- {{ category || i18n.ts.other }}
+ {{ child.value || i18n.ts.other }}
- {{ category }}
+ {{ category }}
@@ -100,7 +102,14 @@ SPDX-License-Identifier: AGPL-3.0-only
import { ref, shallowRef, computed, watch, onMounted } from 'vue';
import * as Misskey from 'misskey-js';
import XSection from '@/components/MkEmojiPicker.section.vue';
-import { emojilist, emojiCharByCategory, UnicodeEmojiDef, unicodeEmojiCategories as categories, getEmojiName } from '@/scripts/emojilist.js';
+import {
+ emojilist,
+ emojiCharByCategory,
+ UnicodeEmojiDef,
+ unicodeEmojiCategories as categories,
+ getEmojiName,
+ CustomEmojiFolderTree
+} from '@/scripts/emojilist.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue';
import * as os from '@/os.js';
import { isTouchUsing } from '@/scripts/touch.js';
@@ -144,6 +153,35 @@ const searchResultCustom = ref([]);
const searchResultUnicode = ref([]);
const tab = ref<'index' | 'custom' | 'unicode' | 'tags'>('index');
+const customEmojiFolderRoot: CustomEmojiFolderTree = { value: "", category: "", children: [] };
+
+function parseAndMergeCategories(input: string, root: CustomEmojiFolderTree): CustomEmojiFolderTree {
+ const parts = input.split('/').map(p => p.trim());
+ let currentNode: CustomEmojiFolderTree = root;
+
+ for (const part of parts) {
+ let existingNode = currentNode.children.find((node) => node.value === part);
+
+ if (!existingNode) {
+ const newNode: CustomEmojiFolderTree = { value: part, category: input, children: [] };
+ currentNode.children.push(newNode);
+ existingNode = newNode;
+ }
+
+ currentNode = existingNode;
+ }
+
+ return currentNode;
+}
+
+customEmojiCategories.value.forEach(ec => {
+ if (ec !== null) {
+ parseAndMergeCategories(ec, customEmojiFolderRoot);
+ }
+});
+
+parseAndMergeCategories('', customEmojiFolderRoot);
+
watch(q, () => {
if (emojisEl.value) emojisEl.value.scrollTop = 0;
@@ -572,8 +610,7 @@ defineExpose({
position: sticky;
top: 0;
left: 0;
- height: 32px;
- line-height: 32px;
+ line-height: 28px;
z-index: 1;
padding: 0 8px;
font-size: 12px;
diff --git a/packages/frontend/src/scripts/emojilist.ts b/packages/frontend/src/scripts/emojilist.ts
index 4159da84c8..8885bf4b7f 100644
--- a/packages/frontend/src/scripts/emojilist.ts
+++ b/packages/frontend/src/scripts/emojilist.ts
@@ -43,3 +43,9 @@ export function getEmojiName(char: string): string | null {
return emojilist[idx].name;
}
}
+
+export interface CustomEmojiFolderTree {
+ value: string;
+ category: string;
+ children: CustomEmojiFolderTree[];
+}