Skip to content

Commit

Permalink
絵文字ピッカーのタグ欄の改善 (#325)
Browse files Browse the repository at this point in the history
* タグの境界線色と背景色などの調整

* タグ欄下の境界線が消えていたのを修正

* タグ間の余白の取り方を修正

* 設定画面のタグ欄のカスタマイズ時に任意の文字列を入力させるのではなく、タグ一覧から選択するように

* タグ欄のカスタマイズで任意の名前を設定できるように

* localesの修正

* タグ欄にカスタム絵文字を表示できるように

* スタイルを微調整

* fix

* ラベルについてのキャプションを追加

* タグ欄に関連するものがクライアント設定のバックアップに含まれるように
  • Loading branch information
adzukimame authored Nov 30, 2024
1 parent 0e808ef commit 6c19c26
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 92 deletions.
3 changes: 2 additions & 1 deletion locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ pinnedEmojisSettingDescription: "Set the emojis to be pinned and displayed when
emojiPickerDisplay: "Emoji picker display"
emojiPickerTagSection: "Show a tag field in the emoji picker"
emojiPickerTagOneline: "Limit the tag field of the emoji picker to one line."
emojiPickerTags: "Tags to be shown in the tag field of the emoji picker."
emojiPickerTags: "Customize the tag field of the emoji picker."
emojiPickerTagsDescription: "If you use a emoji in a label, you can use exactly one emoji and you cannot include other characters."
overwriteFromPinnedEmojisForReaction: "Override from reaction settings"
overwriteFromPinnedEmojis: "Override from general settings"
reactionSettingDescription2: "Drag to reorder, click to delete, press \"+\" to add."
Expand Down
6 changes: 5 additions & 1 deletion locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,9 +555,13 @@ export interface Locale extends ILocale {
*/
"emojiPickerTagOneline": string;
/**
* 絵文字ピッカーのタグ欄に表示するタグ
* 絵文字ピッカーのタグ欄のカスタマイズ
*/
"emojiPickerTags": string;
/**
* ラベルに絵文字を使用する場合、一つしか含めることはできず、他の文字列を含めることもできません。
*/
"emojiPickerTagsDescription": string;
/**
* リアクション設定から上書きする
*/
Expand Down
3 changes: 2 additions & 1 deletion locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ pinnedEmojisSettingDescription: "絵文字入力時にピン留め表示する
emojiPickerDisplay: "ピッカーの表示"
emojiPickerTagSection: "絵文字ピッカーにタグ欄を表示する"
emojiPickerTagOneline: "絵文字ピッカーのタグ欄を1行に制限する"
emojiPickerTags: "絵文字ピッカーのタグ欄に表示するタグ"
emojiPickerTags: "絵文字ピッカーのタグ欄のカスタマイズ"
emojiPickerTagsDescription: "ラベルに絵文字を使用する場合、一つしか含めることはできず、他の文字列を含めることもできません。"
overwriteFromPinnedEmojisForReaction: "リアクション設定から上書きする"
overwriteFromPinnedEmojis: "全般設定から上書きする"
reactionSettingDescription2: "ドラッグして並び替え、クリックして削除、+を押して追加します。"
Expand Down
70 changes: 40 additions & 30 deletions packages/frontend/src/components/MkEmojiPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ SPDX-License-Identifier: AGPL-3.0-only
>
<!-- FirefoxのTabフォーカスが想定外の挙動となるためtabindex="-1"を追加 https://github.com/misskey-dev/misskey/issues/10744 -->
<div ref="emojisEl" class="emojis" tabindex="-1">
<div v-if="defaultStore.reactiveState.emojiPickerTagSection.value && pinnedTags.length > 0" :class="{ oneline: defaultStore.reactiveState.emojiPickerTagOneline.value }" class="tags">
<button v-for="tag in pinnedTags" :key="tag" class="_button tag" :class="{ selected: selectedTags.has(tag) }" :disabled="!availableTags.has(tag)" @click="() => selectedTags.has(tag) ? selectedTags.delete(tag) : selectedTags.add(tag)">{{ tag }}</button>
<div v-if="defaultStore.reactiveState.emojiPickerTagSection.value && Object.keys(pinnedTagPairs).length > 0" :class="{ oneline: defaultStore.reactiveState.emojiPickerTagOneline.value }" class="tags">
<button v-for="(tag, name) in pinnedTagPairs" :key="name" class="_button tag" :class="{ selected: selectedTagNames.has(name) }" :disabled="!availableTagNames.has(name)" @click="() => selectedTagNames.has(name) ? selectedTagNames.delete(name) : selectedTagNames.add(name)">
<MkEmoji v-if="typeof getUnicodeEmoji(name) === 'object'" class="emoji" :emoji="(getUnicodeEmoji(name) as Exclude<ReturnType<typeof getUnicodeEmoji>, string>).char"/>
<MkCustomEmoji v-else-if="name.startsWith(':') && name.indexOf(':', 1) === name.length - 1" class="emoji customEmoji" :name="name"/>
<span v-else>{{ name }}</span>
</button>
</div>

<section class="result">
Expand Down Expand Up @@ -169,11 +173,11 @@ const recentlyUsedEmojisDef = computed(() => {
const pinnedEmojisDef = computed(() => {
return pinned.value?.map(getDef);
});
const pinnedTags = computed<string[]>(() => {
if (defaultStore.reactiveState.emojiPickerTags.value.length === 0) {
return customEmojiTags.value;
const pinnedTagPairs = computed<Record<string, string>>(() => {
if (Object.keys(defaultStore.reactiveState.emojiPickerTagPairs.value).length === 0) {
return Object.fromEntries(customEmojiTags.value.map(tag => [tag, tag]));
} else {
return defaultStore.reactiveState.emojiPickerTags.value.filter(tag => customEmojiTags.value.includes(tag));
return defaultStore.reactiveState.emojiPickerTagPairs.value;
}
});

Expand All @@ -182,23 +186,23 @@ const size = computed(() => emojiPickerScale.value);
const width = computed(() => emojiPickerWidth.value);
const height = computed(() => emojiPickerHeight.value);
const q = ref<string>('');
const selectedTags = reactive(new Set<string>());
const selectedTagNames = reactive(new Set<string>());
const searchResultCustom = ref<EmojiSimple[]>([]);
const searchResultUnicode = ref<UnicodeEmojiDef[]>([]);

const availableTags = computed<Set<string>>(() => {
if (selectedTags.size === 0) return new Set(pinnedTags.value);
const availableTagNames = computed<Set<string>>(() => {
if (selectedTagNames.size === 0) return new Set(Object.keys(pinnedTagPairs.value));

let tags = new Set<string>(pinnedTags.value);
for (const selectedTag of selectedTags) {
if (customEmojiTagCombinations.value.has(selectedTag)) {
tags = tags.intersection(customEmojiTagCombinations.value.get(selectedTag)!);
let tags = new Set<string>(Object.values(pinnedTagPairs.value));
for (const selectedTagName of selectedTagNames) {
if (customEmojiTagCombinations.value.has(pinnedTagPairs.value[selectedTagName])) {
tags = tags.intersection(customEmojiTagCombinations.value.get(pinnedTagPairs.value[selectedTagName])!);
} else {
tags = selectedTags;
break;
return new Set<string>(selectedTagNames);
}
}
return tags;

return new Set<string>(Object.keys(pinnedTagPairs.value).filter(name => tags.has(pinnedTagPairs.value[name])));
});

const customEmojiFolderRoot: CustomEmojiFolderTree = { value: '', category: '', children: [] };
Expand Down Expand Up @@ -230,11 +234,11 @@ customEmojiCategories.value.forEach(ec => {

parseAndMergeCategories('', customEmojiFolderRoot);

watch([q, selectedTags], () => {
watch([q, selectedTagNames], () => {
if (emojisEl.value) emojisEl.value.scrollTop = 0;

// 検索クエリなし かつ タグ選択なし なら 検索結果は空
if (q.value === '' && selectedTags.size === 0) {
if (q.value === '' && selectedTagNames.size === 0) {
searchResultCustom.value = [];
searchResultUnicode.value = [];
return;
Expand All @@ -245,16 +249,16 @@ watch([q, selectedTags], () => {
const newQ = q.value.replace(/:/g, '').toLowerCase().trim();

// 検索クエリなし かつ タグ選択なし なら 検索結果は空
if (newQ === '' && selectedTags.size === 0) {
if (newQ === '' && selectedTagNames.size === 0) {
searchResultCustom.value = [];
searchResultUnicode.value = [];
return;
}

const searchCustom = () => {
const MAX = 100;
const selectedTagsArray = Array.from(selectedTags);
const emojis = customEmojis.value.filter(emoji => selectedTagsArray.length === 0 || selectedTagsArray.every(selectedTag => emoji.tags.includes(selectedTag)));
const selectedTagsArray: string[] = Array.from(selectedTagNames).map(name => pinnedTagPairs.value[name]);
const emojis = selectedTagsArray.length === 0 ? customEmojis.value : customEmojis.value.filter(emoji => selectedTagsArray.every(selectedTag => emoji.tags.includes(selectedTag)));
const matches = new Set<EmojiSimple>();

if (newQ === '') {
Expand Down Expand Up @@ -441,7 +445,7 @@ watch([q, selectedTags], () => {
};

searchResultCustom.value = Array.from(searchCustom());
searchResultUnicode.value = selectedTags.size > 0 ? [] : Array.from(searchUnicode());
searchResultUnicode.value = selectedTagNames.size > 0 ? [] : Array.from(searchUnicode());
});

function canReact(emoji: EmojiSimple | UnicodeEmojiDef | string): boolean {
Expand All @@ -463,7 +467,7 @@ function focus() {
function reset() {
if (emojisEl.value) emojisEl.value.scrollTop = 0;
q.value = '';
selectedTags.clear();
selectedTagNames.clear();
}

function getKey(emoji: string | EmojiSimple | UnicodeEmojiDef): string {
Expand Down Expand Up @@ -745,9 +749,10 @@ defineExpose({
width: 100%;
padding: 12px;
box-sizing: border-box;
border-bottom: solid 0.5px var(--divider);
border-bottom: solid 0.5px var(--MI_THEME-divider);
display: flex;
flex-wrap: wrap;
gap: 6px;

&.oneline {
flex-wrap: nowrap;
Expand All @@ -757,12 +762,10 @@ defineExpose({
> .tag {
color: var(--MI_THEME-fg);
background: var(--MI_THEME-buttonBg);
border: 1px solid var(--MI_THEME-buttonBg);
border: 1px solid var(--MI_THEME-divider);
border-radius: 5px;
padding-inline: 0.5em;
padding-block: 0.2rem;
margin-inline: 4px;
margin-block: 4px;
padding-block: 0.2em;
white-space: nowrap;

&:hover {
Expand All @@ -777,8 +780,15 @@ defineExpose({
cursor: default;
background: linear-gradient(-45deg, transparent 0% 48%, var(--X6) 48% 52%, transparent 52% 100%);
filter: grayscale(1);
mix-blend-mode: exclusion;
opacity: 0.8;
opacity: 0.6;
}

.customEmoji {
height: 1.25em;

&:hover {
transform: none;
}
}
}
}
Expand Down
Loading

0 comments on commit 6c19c26

Please sign in to comment.