summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2020-11-14 11:47:30 +0900
committersyuilo <syuilotan@yahoo.co.jp>2020-11-14 11:47:30 +0900
commit9c9cd168ee0c8a9d2528ef2eda6f7de0b8d8da41 (patch)
treec26440edbb46a4de77a31e64dce4a0e504921b54
parentFix #6832 (diff)
downloadsharkey-9c9cd168ee0c8a9d2528ef2eda6f7de0b8d8da41.tar.gz
sharkey-9c9cd168ee0c8a9d2528ef2eda6f7de0b8d8da41.tar.bz2
sharkey-9c9cd168ee0c8a9d2528ef2eda6f7de0b8d8da41.zip
Improve emoji picker
-rw-r--r--src/client/components/emoji-picker.vue93
-rw-r--r--src/client/components/note.vue44
-rw-r--r--src/client/components/reaction-picker.vue214
-rw-r--r--src/client/pages/settings/reaction.vue17
4 files changed, 75 insertions, 293 deletions
diff --git a/src/client/components/emoji-picker.vue b/src/client/components/emoji-picker.vue
index 270951962f..5d60f2eb51 100644
--- a/src/client/components/emoji-picker.vue
+++ b/src/client/components/emoji-picker.vue
@@ -1,7 +1,7 @@
<template>
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
- <div class="omfetrab _popup">
- <input ref="search" class="search" v-model.trim="q" :placeholder="$t('search')" @paste.stop="paste" @keyup.enter="done()" autofocus>
+ <div class="omfetrab _popup" :class="{ compact }">
+ <input ref="search" class="search" :class="{ filled: q != null && q != '' }" v-model.trim="q" :placeholder="$t('search')" @paste.stop="paste" @keyup.enter="done()">
<div class="emojis">
<section class="result">
<div v-if="searchResultCustom.length > 0">
@@ -43,7 +43,7 @@
</section>
<section>
- <header class="_acrylic"><Fa :icon="faHistory" fixed-width/> {{ $t('recentUsed') }}</header>
+ <header class="_acrylic"><Fa :icon="faClock" fixed-width/> {{ $t('recentUsed') }}</header>
<div>
<button v-for="emoji in $store.state.device.recentlyUsedEmojis"
class="_button"
@@ -94,7 +94,7 @@
import { defineComponent, markRaw } from 'vue';
import { emojilist } from '../../misc/emojilist';
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
-import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory, faUser, faChevronDown } from '@fortawesome/free-solid-svg-icons';
+import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faClock, faUser, faChevronDown } from '@fortawesome/free-solid-svg-icons';
import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
import MkModal from '@/components/ui/modal.vue';
import Particle from '@/components/particle.vue';
@@ -112,6 +112,9 @@ export default defineComponent({
overridePinned: {
required: false
},
+ compact: {
+ required: false
+ },
},
emits: ['done', 'closed'],
@@ -127,7 +130,7 @@ export default defineComponent({
q: null,
searchResultCustom: [],
searchResultUnicode: [],
- faGlobe, faHistory, faChevronDown,
+ faGlobe, faClock, faChevronDown,
categories: [{
name: 'face',
icon: faLaugh,
@@ -311,9 +314,12 @@ export default defineComponent({
},
mounted() {
- this.$refs.search.focus({
- preventScroll: true
- });
+ const isIos = navigator.userAgent.includes('WebKit') && !navigator.userAgent.includes('Chrome');
+ if (!isIos) {
+ this.$refs.search.focus({
+ preventScroll: true
+ });
+ }
},
methods: {
@@ -379,8 +385,19 @@ export default defineComponent({
<style lang="scss" scoped>
.omfetrab {
- width: 350px;
+ $eachSize: 40px;
+ $pad: 8px;
+
+ display: flex;
+ flex-direction: column;
+ width: ($eachSize * 7) + ($pad * 2);
contain: content;
+ --height: 300px;
+
+ &.compact {
+ width: ($eachSize * 5) + ($pad * 2);
+ --height: 210px;
+ }
> .search {
width: 100%;
@@ -391,17 +408,27 @@ export default defineComponent({
border: none;
background: transparent;
color: var(--fg);
+
+ &:not(.filled) {
+ order: 1;
+ z-index: 2;
+ box-shadow: 0px -1px 0 0px var(--divider);
+ }
}
> .emojis {
- $height: 300px;
-
- height: $height;
+ height: var(--height);
overflow-y: auto;
overflow-x: hidden;
+ scrollbar-width: none;
+
+ &::-webkit-scrollbar {
+ display: none;
+ }
+
> .index {
- min-height: $height;
+ min-height: var(--height);
position: relative;
border-bottom: solid 1px var(--divider);
@@ -428,45 +455,33 @@ export default defineComponent({
}
> div {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
- gap: 4px;
- padding: 8px;
+ padding: $pad;
> button {
position: relative;
padding: 0;
- width: 100%;
+ width: $eachSize;
+ height: $eachSize;
+ border-radius: 4px;
&:focus {
outline: solid 2px var(--focus);
z-index: 1;
}
- &:before {
- content: '';
- display: block;
- width: 1px;
- height: 0;
- padding-bottom: 100%;
+ &:hover {
+ background: rgba(0, 0, 0, 0.05);
}
- &:hover {
- > * {
- transform: scale(1.2);
- transition: transform 0s;
- }
+ &:active {
+ background: var(--accent);
+ box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15);
}
> * {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- object-fit: contain;
- font-size: 28px;
- transition: transform 0.2s ease;
+ font-size: 24px;
+ height: 1.25em;
+ vertical-align: -.25em;
pointer-events: none;
}
}
@@ -474,6 +489,10 @@ export default defineComponent({
&.result {
border-bottom: solid 1px var(--divider);
+
+ &:empty {
+ display: none;
+ }
}
&.unicode {
diff --git a/src/client/components/note.vue b/src/client/components/note.vue
index 53972d9f6f..bf89cbf568 100644
--- a/src/client/components/note.vue
+++ b/src/client/components/note.vue
@@ -498,36 +498,20 @@ export default defineComponent({
react(viaKeyboard = false) {
pleaseLogin();
this.blur();
- if (this.$store.state.device.useFullReactionPicker) {
- os.popup(import('@/components/emoji-picker.vue'), {
- src: this.$refs.reactButton,
- }, {
- done: reaction => {
- if (reaction) {
- os.api('notes/reactions/create', {
- noteId: this.appearNote.id,
- reaction: reaction
- });
- }
- this.focus();
- },
- }, 'closed');
- } else {
- os.popup(import('@/components/reaction-picker.vue'), {
- showFocus: viaKeyboard,
- src: this.$refs.reactButton,
- }, {
- done: reaction => {
- if (reaction) {
- os.api('notes/reactions/create', {
- noteId: this.appearNote.id,
- reaction: reaction
- });
- }
- this.focus();
- },
- }, 'closed');
- }
+ os.popup(import('@/components/emoji-picker.vue'), {
+ src: this.$refs.reactButton,
+ compact: !this.$store.state.device.useFullReactionPicker
+ }, {
+ done: reaction => {
+ if (reaction) {
+ os.api('notes/reactions/create', {
+ noteId: this.appearNote.id,
+ reaction: reaction
+ });
+ }
+ this.focus();
+ },
+ }, 'closed');
},
reactDirectly(reaction) {
diff --git a/src/client/components/reaction-picker.vue b/src/client/components/reaction-picker.vue
deleted file mode 100644
index fca1e858bb..0000000000
--- a/src/client/components/reaction-picker.vue
+++ /dev/null
@@ -1,214 +0,0 @@
-<template>
-<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
- <div class="rdfaahpb _popup" v-hotkey="keymap">
- <div class="buttons" ref="buttons" :class="{ showFocus }">
- <button class="_button" v-for="(reaction, i) in rs" :key="reaction" @click="react(reaction)" :tabindex="i + 1" :title="reaction" v-particle><XReactionIcon :reaction="reaction"/></button>
- </div>
- <input class="text" ref="text" v-model.trim="text" :placeholder="$t('enterEmoji')" @keyup.enter="reactText" @input="tryReactText">
- </div>
-</MkModal>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import { emojiRegex } from '../../misc/emoji-regex';
-import XReactionIcon from '@/components/reaction-icon.vue';
-import MkModal from '@/components/ui/modal.vue';
-import { Autocomplete } from '@/scripts/autocomplete';
-
-export default defineComponent({
- components: {
- XReactionIcon,
- MkModal,
- },
-
- props: {
- reactions: {
- required: false
- },
-
- showFocus: {
- type: Boolean,
- required: false,
- default: false
- },
-
- src: {
- required: false
- },
- },
-
- emits: ['done', 'closed'],
-
- data() {
- return {
- rs: this.reactions || this.$store.state.settings.reactions,
- text: null,
- focus: null
- };
- },
-
- computed: {
- keymap(): any {
- return {
- 'esc': this.close,
- 'enter|space|plus': this.choose,
- 'up|k': this.focusUp,
- 'left|h|shift+tab': this.focusLeft,
- 'right|l|tab': this.focusRight,
- 'down|j': this.focusDown,
- '1': () => this.react(this.rs[0]),
- '2': () => this.react(this.rs[1]),
- '3': () => this.react(this.rs[2]),
- '4': () => this.react(this.rs[3]),
- '5': () => this.react(this.rs[4]),
- '6': () => this.react(this.rs[5]),
- '7': () => this.react(this.rs[6]),
- '8': () => this.react(this.rs[7]),
- '9': () => this.react(this.rs[8]),
- '0': () => this.react(this.rs[9]),
- };
- },
- },
-
- watch: {
- focus(i) {
- this.$refs.buttons.children[i].focus({
- preventScroll: true
- });
- }
- },
-
- mounted() {
- this.$nextTick(() => {
- this.focus = 0;
- });
-
- // TODO: detach when unmount
- new Autocomplete(this.$refs.text, this, { model: 'text' });
- },
-
- methods: {
- close() {
- this.$emit('done');
- this.$refs.modal.close();
- },
-
- react(reaction) {
- this.$emit('done', reaction);
- this.$refs.modal.close();
- },
-
- reactText() {
- if (!this.text) return;
- this.react(this.text);
- },
-
- tryReactText() {
- if (!this.text) return;
- if (!this.text.match(emojiRegex)) return;
- this.reactText();
- },
-
- focusUp() {
- this.focus = this.focus == 0 ? 9 : this.focus < 5 ? (this.focus + 4) : (this.focus - 5);
- },
-
- focusDown() {
- this.focus = this.focus == 9 ? 0 : this.focus >= 5 ? (this.focus - 4) : (this.focus + 5);
- },
-
- focusRight() {
- this.focus = this.focus == 9 ? 0 : (this.focus + 1);
- },
-
- focusLeft() {
- this.focus = this.focus == 0 ? 9 : (this.focus - 1);
- },
-
- choose() {
- this.$refs.buttons.children[this.focus].click();
- },
- }
-});
-</script>
-
-<style lang="scss" scoped>
-.rdfaahpb {
- > .buttons {
- padding: 6px 6px 0 6px;
- width: 212px;
- box-sizing: border-box;
- text-align: center;
-
- @media (max-width: 1025px) {
- padding: 8px 8px 0 8px;
- width: 256px;
- }
-
- &.showFocus {
- > button:focus {
- position: relative;
- z-index: 1;
-
- &:after {
- content: "";
- pointer-events: none;
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- border: 2px solid var(--focus);
- border-radius: 4px;
- }
- }
- }
-
- > button {
- padding: 0;
- width: 40px;
- height: 40px;
- font-size: 24px;
- border-radius: 2px;
-
- @media (max-width: 1025px) {
- width: 48px;
- height: 48px;
- font-size: 26px;
- }
-
- > * {
- height: 1em;
- }
-
- &:hover {
- background: rgba(0, 0, 0, 0.05);
- }
-
- &:active {
- background: var(--accent);
- box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15);
- }
- }
- }
-
- > .text {
- width: 208px;
- padding: 8px;
- margin: 0 0 6px 0;
- box-sizing: border-box;
- text-align: center;
- font-size: 16px;
- outline: none;
- border: none;
- background: transparent;
- color: var(--fg);
-
- @media (max-width: 1025px) {
- width: 256px;
- margin: 4px 0 8px 0;
- }
- }
-}
-</style>
diff --git a/src/client/pages/settings/reaction.vue b/src/client/pages/settings/reaction.vue
index 8033b7e11d..52b9f3260b 100644
--- a/src/client/pages/settings/reaction.vue
+++ b/src/client/pages/settings/reaction.vue
@@ -80,18 +80,11 @@ export default defineComponent({
},
preview(ev) {
- if (this.$store.state.device.useFullReactionPicker) {
- os.popup(import('@/components/emoji-picker.vue'), {
- overridePinned: this.splited,
- src: ev.currentTarget || ev.target,
- }, {}, 'closed');
- } else {
- os.popup(import('@/components/reaction-picker.vue'), {
- reactions: this.splited,
- showFocus: false,
- src: ev.currentTarget || ev.target,
- }, {}, 'closed');
- }
+ os.popup(import('@/components/emoji-picker.vue'), {
+ overridePinned: this.splited,
+ compact: !this.$store.state.device.useFullReactionPicker,
+ src: ev.currentTarget || ev.target,
+ }, {}, 'closed');
},
setDefault() {