Skip to content
Snippets Groups Projects
Commit ebb53e87 authored by syuilo's avatar syuilo
Browse files

ハッシュタグ入力エリア

Resolve #7600
parent 9f9d7325
No related branches found
No related tags found
No related merge requests found
......@@ -768,6 +768,7 @@ squareAvatars: "アイコンを四角形で表示"
sent: "送信"
received: "受信"
searchResult: "検索結果"
hashtags: "ハッシュタグ"
_docs:
continueReading: "続きを読む"
......
......@@ -37,6 +37,7 @@
<MkInfo warn v-if="hasNotSpecifiedMentions" class="hasNotSpecifiedMentions">{{ $ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ $ts.add }}</button></MkInfo>
<input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$ts.annotation" @keydown="onKeydown">
<textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd" />
<input v-show="withHashtags" ref="hashtags" class="hashtags" v-model="hashtags" :placeholder="$ts.hashtags" list="hashtags">
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
<footer>
......@@ -44,9 +45,13 @@
<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><i class="fas fa-poll-h"></i></button>
<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$ts.useCw"><i class="fas fa-eye-slash"></i></button>
<button class="_button" @click="insertMention" v-tooltip="$ts.mention"><i class="fas fa-at"></i></button>
<button class="_button" @click="withHashtags = !withHashtags" v-tooltip="$ts.hashtags"><i class="fas fa-hashtag"></i></button>
<button class="_button" @click="insertEmoji" v-tooltip="$ts.emoji"><i class="fas fa-laugh-squint"></i></button>
<button class="_button" @click="showActions" v-tooltip="$ts.plugin" v-if="postFormActions.length > 0"><i class="fas fa-plug"></i></button>
</footer>
<datalist id="hashtags">
<option v-for="hashtag in recentHashtags" :value="hashtag" :key="hashtag"/>
</datalist>
</div>
</div>
</template>
......@@ -67,10 +72,11 @@ import { Autocomplete } from '@client/scripts/autocomplete';
import { noteVisibilities } from '../../types';
import * as os from '@client/os';
import { selectFile } from '@client/scripts/select-file';
import { notePostInterruptors, postFormActions } from '@client/store';
import { defaultStore, notePostInterruptors, postFormActions } from '@client/store';
import { isMobile } from '@client/scripts/is-mobile';
import { throttle } from 'throttle-debounce';
import MkInfo from '@client/components/ui/info.vue';
import { defaultStore } from '@client/store';
export default defineComponent({
components: {
......@@ -212,7 +218,10 @@ export default defineComponent({
max(): number {
return this.$instance ? this.$instance.maxNoteTextLength : 1000;
}
},
withHashtags: defaultStore.makeGetterSetter('postFormWithHashtags'),
hashtags: defaultStore.makeGetterSetter('postFormHashtags'),
},
watch: {
......@@ -303,6 +312,7 @@ export default defineComponent({
// TODO: detach when unmount
new Autocomplete(this.$refs.text, this, { model: 'text' });
new Autocomplete(this.$refs.cw, this, { model: 'cw' });
new Autocomplete(this.$refs.hashtags, this, { model: 'hashtags' });
this.$nextTick(() => {
// 書きかけの投稿を復元
......@@ -605,6 +615,11 @@ export default defineComponent({
viaMobile: isMobile
};
if (this.withHashtags) {
const hashtags = this.hashtags.trim().split(' ').map(x => x.startsWith('#') ? x : '#' + x).join(' ');
data.text = data.text ? `${data.text} ${hashtags}` : hashtags;
}
// plugin
if (notePostInterruptors.length > 0) {
for (const interruptor of notePostInterruptors) {
......@@ -618,8 +633,8 @@ export default defineComponent({
this.$nextTick(() => {
this.deleteDraft();
this.$emit('posted');
if (this.text && this.text != '') {
const hashtags = mfm.parse(this.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
if (data.text && data.text != '') {
const hashtags = mfm.parse(data.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
localStorage.setItem('hashtags', JSON.stringify(unique(hashtags.concat(history))));
}
......@@ -785,6 +800,7 @@ export default defineComponent({
}
> .cw,
> .hashtags,
> .text {
display: block;
box-sizing: border-box;
......@@ -813,6 +829,13 @@ export default defineComponent({
border-bottom: solid 0.5px var(--divider);
}
> .hashtags {
z-index: 1;
padding-top: 8px;
padding-bottom: 8px;
border-top: solid 0.5px var(--divider);
}
> .text {
max-width: 100%;
min-width: 100%;
......@@ -872,6 +895,7 @@ export default defineComponent({
}
> .cw,
> .hashtags,
> .text {
padding: 0 16px;
}
......
......@@ -198,6 +198,14 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: false
},
postFormWithHashtags: {
where: 'device',
default: false
},
postFormHashtags: {
where: 'device',
default: ''
},
}));
// TODO: 他のタブと永続化されたstateを同期
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment