mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-22 18:07:31 -07:00
Resolve #7264
This commit is contained in:
parent
5d484ee873
commit
5556ebb176
3 changed files with 143 additions and 98 deletions
52
src/client/components/emoji-picker.section.vue
Normal file
52
src/client/components/emoji-picker.section.vue
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<template>
|
||||||
|
<section>
|
||||||
|
<header class="_acrylic" @click="shown = !shown">
|
||||||
|
<Fa :icon="shown ? faChevronDown : faChevronUp" :key="shown" fixed-width class="toggle"/> <slot></slot> ({{ emojis.length }})
|
||||||
|
</header>
|
||||||
|
<div v-if="shown">
|
||||||
|
<button v-for="emoji in emojis"
|
||||||
|
class="_button"
|
||||||
|
@click="chosen(emoji, $event)"
|
||||||
|
:key="emoji"
|
||||||
|
>
|
||||||
|
<MkEmoji :emoji="emoji" :normal="true"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, markRaw } from 'vue';
|
||||||
|
import { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
emojis: {
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
initialShown: {
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['chosen'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
getStaticImageUrl,
|
||||||
|
shown: this.initialShown,
|
||||||
|
faChevronUp, faChevronDown,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
chosen(emoji: any, ev) {
|
||||||
|
this.$parent.chosen(emoji, ev);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
|
@ -28,7 +28,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="index">
|
<div class="index" v-if="tab === 'index'">
|
||||||
<section v-if="showPinned">
|
<section v-if="showPinned">
|
||||||
<div>
|
<div>
|
||||||
<button v-for="emoji in pinned"
|
<button v-for="emoji in pinned"
|
||||||
|
@ -53,37 +53,31 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="arrow"><Fa :icon="faChevronDown"/></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-appear="() => showingCustomEmojis = true">
|
||||||
<section v-for="category in customEmojiCategories" :key="'custom:' + category" class="custom">
|
<header class="_acrylic">{{ $ts.customEmojis }}</header>
|
||||||
<header class="_acrylic" v-appear="() => visibleCategories[category] = true">{{ category || $ts.other }}</header>
|
<template v-if="showingCustomEmojis">
|
||||||
<div v-if="visibleCategories[category]">
|
<XSection v-for="category in customEmojiCategories" :key="'custom:' + category" :initial-shown="false" :emojis="customEmojis.filter(e => e.category === category).map(e => ':' + e.name + ':')">{{ category || $ts.other }}</XSection>
|
||||||
<button v-for="emoji in customEmojis.filter(e => e.category === category)"
|
</template>
|
||||||
class="_button"
|
|
||||||
:title="emoji.name"
|
|
||||||
@click="chosen(emoji, $event)"
|
|
||||||
:key="emoji.name"
|
|
||||||
>
|
|
||||||
<img :src="$store.state.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
<div v-appear="() => showingEmojis = true">
|
||||||
|
<header class="_acrylic">{{ $ts.emoji }}</header>
|
||||||
<section v-for="category in categories" :key="category.name" class="unicode">
|
<template v-if="showingEmojis">
|
||||||
<header class="_acrylic" v-appear="() => category.isActive = true"><Fa :icon="category.icon" fixed-width/> {{ category.name }}</header>
|
<XSection v-for="category in categories" :emojis="emojilist.filter(e => e.category === category).map(e => e.char)">{{ category }}</XSection>
|
||||||
<div v-if="category.isActive">
|
</template>
|
||||||
<button v-for="emoji in emojilist.filter(e => e.category === category.name)"
|
|
||||||
class="_button"
|
|
||||||
:title="emoji.name"
|
|
||||||
@click="chosen(emoji, $event)"
|
|
||||||
:key="emoji.name"
|
|
||||||
>
|
|
||||||
<MkEmoji :emoji="emoji.char"/>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
<div v-appear="() => showingTags = true">
|
||||||
|
<header class="_acrylic">{{ $ts.tags }}</header>
|
||||||
|
<template v-if="showingTags">
|
||||||
|
<XSection v-for="tag in emojiTags" :emojis="customEmojis.filter(e => e.aliases.includes(tag)).map(e => ':' + e.name + ':')">{{ tag }}</XSection>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tabs">
|
||||||
|
<button class="_button tab" :class="{ active: tab === 'index' }" @click="tab = 'index'"><Fa :icon="faAsterisk" fixed-width/></button>
|
||||||
|
<button class="_button tab" :class="{ active: tab === 'custom' }" @click="tab = 'custom'"><Fa :icon="faLaugh" fixed-width/></button>
|
||||||
|
<button class="_button tab" :class="{ active: tab === 'unicode' }" @click="tab = 'unicode'"><Fa :icon="faLeaf" fixed-width/></button>
|
||||||
|
<button class="_button tab" :class="{ active: tab === 'tags' }" @click="tab = 'tags'"><Fa :icon="faHashtag" fixed-width/></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -92,15 +86,20 @@
|
||||||
import { defineComponent, markRaw } from 'vue';
|
import { defineComponent, markRaw } from 'vue';
|
||||||
import { emojilist } from '../../misc/emojilist';
|
import { emojilist } from '../../misc/emojilist';
|
||||||
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||||
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faClock, faUser, faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faClock, faUser, faChevronDown, faShapes, faBicycle, faHashtag } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
|
import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
|
||||||
import Particle from '@/components/particle.vue';
|
import Particle from '@/components/particle.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { isDeviceTouch } from '@/scripts/is-device-touch';
|
import { isDeviceTouch } from '@/scripts/is-device-touch';
|
||||||
import { isMobile } from '@/scripts/is-mobile';
|
import { isMobile } from '@/scripts/is-mobile';
|
||||||
import { emojiCategories } from '@/instance';
|
import { emojiCategories, emojiTags } from '@/instance';
|
||||||
|
import XSection from './emoji-picker.section.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XSection
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
showPinned: {
|
showPinned: {
|
||||||
required: false,
|
required: false,
|
||||||
|
@ -122,50 +121,17 @@ export default defineComponent({
|
||||||
height: this.asReactionPicker ? this.$store.state.reactionPickerHeight : 2,
|
height: this.asReactionPicker ? this.$store.state.reactionPickerHeight : 2,
|
||||||
big: this.asReactionPicker ? isDeviceTouch : false,
|
big: this.asReactionPicker ? isDeviceTouch : false,
|
||||||
customEmojiCategories: emojiCategories,
|
customEmojiCategories: emojiCategories,
|
||||||
|
emojiTags,
|
||||||
customEmojis: this.$instance.emojis,
|
customEmojis: this.$instance.emojis,
|
||||||
visibleCategories: {},
|
|
||||||
q: null,
|
q: null,
|
||||||
searchResultCustom: [],
|
searchResultCustom: [],
|
||||||
searchResultUnicode: [],
|
searchResultUnicode: [],
|
||||||
faGlobe, faClock, faChevronDown,
|
tab: 'index',
|
||||||
categories: [{
|
showingCustomEmojis: false,
|
||||||
name: 'face',
|
showingEmojis: false,
|
||||||
icon: faLaugh,
|
showingTags: false,
|
||||||
isActive: false
|
categories: ['face', 'people', 'animals_and_nature', 'food_and_drink', 'activity', 'travel_and_places', 'objects', 'symbols', 'flags'],
|
||||||
}, {
|
faGlobe, faClock, faChevronDown, faAsterisk, faLaugh, faUtensils, faLeaf, faShapes, faBicycle, faHashtag,
|
||||||
name: 'people',
|
|
||||||
icon: faUser,
|
|
||||||
isActive: false
|
|
||||||
}, {
|
|
||||||
name: 'animals_and_nature',
|
|
||||||
icon: faLeaf,
|
|
||||||
isActive: false
|
|
||||||
}, {
|
|
||||||
name: 'food_and_drink',
|
|
||||||
icon: faUtensils,
|
|
||||||
isActive: false
|
|
||||||
}, {
|
|
||||||
name: 'activity',
|
|
||||||
icon: faFutbol,
|
|
||||||
isActive: false
|
|
||||||
}, {
|
|
||||||
name: 'travel_and_places',
|
|
||||||
icon: faCity,
|
|
||||||
isActive: false
|
|
||||||
}, {
|
|
||||||
name: 'objects',
|
|
||||||
icon: faDice,
|
|
||||||
isActive: false
|
|
||||||
}, {
|
|
||||||
name: 'symbols',
|
|
||||||
icon: faHeart,
|
|
||||||
isActive: false
|
|
||||||
}, {
|
|
||||||
name: 'flags',
|
|
||||||
icon: faFlag,
|
|
||||||
isActive: false
|
|
||||||
}],
|
|
||||||
faAsterisk
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -342,7 +308,7 @@ export default defineComponent({
|
||||||
let recents = this.$store.state.recentlyUsedEmojis;
|
let recents = this.$store.state.recentlyUsedEmojis;
|
||||||
recents = recents.filter((e: any) => e !== key);
|
recents = recents.filter((e: any) => e !== key);
|
||||||
recents.unshift(key);
|
recents.unshift(key);
|
||||||
this.$store.set('recentlyUsedEmojis', recents.splice(0, 16));
|
this.$store.set('recentlyUsedEmojis', recents.splice(0, 32));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -434,6 +400,22 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .tabs {
|
||||||
|
display: flex;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
> .tab {
|
||||||
|
flex: 1;
|
||||||
|
height: 38px;
|
||||||
|
border-top: solid 1px var(--divider);
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-top: solid 1px var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> .emojis {
|
> .emojis {
|
||||||
height: var(--height);
|
height: var(--height);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
@ -445,34 +427,43 @@ export default defineComponent({
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .index {
|
> div {
|
||||||
min-height: var(--height);
|
&:not(.index) {
|
||||||
position: relative;
|
padding: 4px 0 8px 0;
|
||||||
border-bottom: solid 1px var(--divider);
|
border-top: solid 1px var(--divider);
|
||||||
|
}
|
||||||
|
|
||||||
> .arrow {
|
> header {
|
||||||
position: absolute;
|
/*position: sticky;
|
||||||
bottom: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;*/
|
||||||
width: 100%;
|
height: 32px;
|
||||||
padding: 16px 0;
|
line-height: 32px;
|
||||||
text-align: center;
|
z-index: 2;
|
||||||
opacity: 0.5;
|
padding: 0 8px;
|
||||||
pointer-events: none;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
::v-deep(section) {
|
||||||
> header {
|
> header {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
padding: 8px;
|
padding: 0 8px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
|
position: relative;
|
||||||
padding: $pad;
|
padding: $pad;
|
||||||
|
|
||||||
> button {
|
> button {
|
||||||
|
@ -512,14 +503,6 @@ export default defineComponent({
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.unicode {
|
|
||||||
min-height: 384px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.custom {
|
|
||||||
min-height: 64px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,16 @@ export const emojiCategories = computed(() => {
|
||||||
return Array.from(categories);
|
return Array.from(categories);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const emojiTags = computed(() => {
|
||||||
|
const tags = new Set();
|
||||||
|
for (const emoji of instance.emojis) {
|
||||||
|
for (const tag of emoji.aliases) {
|
||||||
|
tags.add(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Array.from(tags);
|
||||||
|
});
|
||||||
|
|
||||||
// このファイルに書きたくないけどここに書かないと何故かVeturが認識しない
|
// このファイルに書きたくないけどここに書かないと何故かVeturが認識しない
|
||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
|
|
Loading…
Reference in a new issue