parent
9f9d7325fd
commit
ebb53e87f3
@ -768,6 +768,7 @@ squareAvatars: "アイコンを四角形で表示"
|
|||||||
sent: "送信"
|
sent: "送信"
|
||||||
received: "受信"
|
received: "受信"
|
||||||
searchResult: "検索結果"
|
searchResult: "検索結果"
|
||||||
|
hashtags: "ハッシュタグ"
|
||||||
|
|
||||||
_docs:
|
_docs:
|
||||||
continueReading: "続きを読む"
|
continueReading: "続きを読む"
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
<MkInfo warn v-if="hasNotSpecifiedMentions" class="hasNotSpecifiedMentions">{{ $ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ $ts.add }}</button></MkInfo>
|
<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">
|
<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" />
|
<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"/>
|
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
|
||||||
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
|
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
|
||||||
<footer>
|
<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="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="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="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="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>
|
<button class="_button" @click="showActions" v-tooltip="$ts.plugin" v-if="postFormActions.length > 0"><i class="fas fa-plug"></i></button>
|
||||||
</footer>
|
</footer>
|
||||||
|
<datalist id="hashtags">
|
||||||
|
<option v-for="hashtag in recentHashtags" :value="hashtag" :key="hashtag"/>
|
||||||
|
</datalist>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -67,10 +72,11 @@ import { Autocomplete } from '@client/scripts/autocomplete';
|
|||||||
import { noteVisibilities } from '../../types';
|
import { noteVisibilities } from '../../types';
|
||||||
import * as os from '@client/os';
|
import * as os from '@client/os';
|
||||||
import { selectFile } from '@client/scripts/select-file';
|
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 { isMobile } from '@client/scripts/is-mobile';
|
||||||
import { throttle } from 'throttle-debounce';
|
import { throttle } from 'throttle-debounce';
|
||||||
import MkInfo from '@client/components/ui/info.vue';
|
import MkInfo from '@client/components/ui/info.vue';
|
||||||
|
import { defaultStore } from '@client/store';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -212,7 +218,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
max(): number {
|
max(): number {
|
||||||
return this.$instance ? this.$instance.maxNoteTextLength : 1000;
|
return this.$instance ? this.$instance.maxNoteTextLength : 1000;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
withHashtags: defaultStore.makeGetterSetter('postFormWithHashtags'),
|
||||||
|
hashtags: defaultStore.makeGetterSetter('postFormHashtags'),
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
@ -303,6 +312,7 @@ export default defineComponent({
|
|||||||
// TODO: detach when unmount
|
// TODO: detach when unmount
|
||||||
new Autocomplete(this.$refs.text, this, { model: 'text' });
|
new Autocomplete(this.$refs.text, this, { model: 'text' });
|
||||||
new Autocomplete(this.$refs.cw, this, { model: 'cw' });
|
new Autocomplete(this.$refs.cw, this, { model: 'cw' });
|
||||||
|
new Autocomplete(this.$refs.hashtags, this, { model: 'hashtags' });
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
// 書きかけの投稿を復元
|
// 書きかけの投稿を復元
|
||||||
@ -605,6 +615,11 @@ export default defineComponent({
|
|||||||
viaMobile: isMobile
|
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
|
// plugin
|
||||||
if (notePostInterruptors.length > 0) {
|
if (notePostInterruptors.length > 0) {
|
||||||
for (const interruptor of notePostInterruptors) {
|
for (const interruptor of notePostInterruptors) {
|
||||||
@ -618,8 +633,8 @@ export default defineComponent({
|
|||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.deleteDraft();
|
this.deleteDraft();
|
||||||
this.$emit('posted');
|
this.$emit('posted');
|
||||||
if (this.text && this.text != '') {
|
if (data.text && data.text != '') {
|
||||||
const hashtags = mfm.parse(this.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
|
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[];
|
const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
|
||||||
localStorage.setItem('hashtags', JSON.stringify(unique(hashtags.concat(history))));
|
localStorage.setItem('hashtags', JSON.stringify(unique(hashtags.concat(history))));
|
||||||
}
|
}
|
||||||
@ -785,6 +800,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
> .cw,
|
> .cw,
|
||||||
|
> .hashtags,
|
||||||
> .text {
|
> .text {
|
||||||
display: block;
|
display: block;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -813,6 +829,13 @@ export default defineComponent({
|
|||||||
border-bottom: solid 0.5px var(--divider);
|
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 {
|
> .text {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
@ -872,6 +895,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
> .cw,
|
> .cw,
|
||||||
|
> .hashtags,
|
||||||
> .text {
|
> .text {
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
}
|
}
|
||||||
|
@ -198,6 +198,14 @@ export const defaultStore = markRaw(new Storage('base', {
|
|||||||
where: 'device',
|
where: 'device',
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
postFormWithHashtags: {
|
||||||
|
where: 'device',
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
postFormHashtags: {
|
||||||
|
where: 'device',
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
Loading…
Reference in New Issue
Block a user