最近使ったハッシュタグを表示するようにするなど

This commit is contained in:
syuilo 2018-07-20 05:29:56 +09:00
parent f42460de47
commit 8f4a638133
5 changed files with 211 additions and 18358 deletions

1
.npmrc
View file

@ -1 +1,2 @@
save-exact=true save-exact=true
package-lock = false

18198
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -126,6 +126,7 @@
"highlight.js": "9.12.0", "highlight.js": "9.12.0",
"html-minifier": "3.5.19", "html-minifier": "3.5.19",
"http-signature": "1.2.0", "http-signature": "1.2.0",
"insert-text-at-cursor": "0.1.1",
"is-root": "2.0.0", "is-root": "2.0.0",
"is-url": "1.2.4", "is-url": "1.2.4",
"jquery": "3.3.1", "jquery": "3.3.1",
@ -205,6 +206,7 @@
"vue-json-tree-view": "2.1.4", "vue-json-tree-view": "2.1.4",
"vue-loader": "15.2.6", "vue-loader": "15.2.6",
"vue-router": "3.0.1", "vue-router": "3.0.1",
"vue-style-loader": "4.1.1",
"vue-template-compiler": "2.5.16", "vue-template-compiler": "2.5.16",
"vuedraggable": "2.16.0", "vuedraggable": "2.16.0",
"vuex": "3.0.1", "vuex": "3.0.1",

View file

@ -10,6 +10,9 @@
<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span> <span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
<a @click="addVisibleUser">+ユーザーを追加</a> <a @click="addVisibleUser">+ユーザーを追加</a>
</div> </div>
<div class="hashtags" v-if="recentHashtags.length > 0">
<a v-for="tag in recentHashtags" @click="addTag(tag)">#{{ tag }}</a>
</div>
<input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)"> <input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)">
<textarea :class="{ with: (files.length != 0 || poll) }" <textarea :class="{ with: (files.length != 0 || poll) }"
ref="text" v-model="text" :disabled="posting" ref="text" v-model="text" :disabled="posting"
@ -46,6 +49,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import insertTextAtCursor from 'insert-text-at-cursor';
import * as XDraggable from 'vuedraggable'; import * as XDraggable from 'vuedraggable';
import getKao from '../../../common/scripts/get-kao'; import getKao from '../../../common/scripts/get-kao';
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue'; import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
@ -91,7 +95,8 @@ export default Vue.extend({
visibility: 'public', visibility: 'public',
visibleUsers: [], visibleUsers: [],
autocomplete: null, autocomplete: null,
draghover: false draghover: false,
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]')
}; };
}, },
@ -183,6 +188,10 @@ export default Vue.extend({
}, },
methods: { methods: {
addTag(tag: string) {
insertTextAtCursor(this.$refs.text, ` #${tag} `);
},
watch() { watch() {
this.$watch('text', () => this.saveDraft()); this.$watch('text', () => this.saveDraft());
this.$watch('poll', () => this.saveDraft()); this.$watch('poll', () => this.saveDraft());
@ -370,6 +379,13 @@ export default Vue.extend({
}).then(() => { }).then(() => {
this.posting = false; this.posting = false;
}); });
if (this.text && this.text != '') {
const hashtags = parse(this.text).filter(x => x.type == 'hashtag').map(x => x.hashtag);
let history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
history = history.filter(x => !hashtags.includes(x));
localStorage.setItem('hashtags', JSON.stringify(hashtags.concat(history)));
}
}, },
saveDraft() { saveDraft() {
@ -478,6 +494,10 @@ root(isDark)
margin-right 16px margin-right 16px
color isDark ? #fff : #666 color isDark ? #fff : #666
> .hashtags
> *
margin-right 8px
> .medias > .medias
margin 0 margin 0
padding 0 padding 0

View file

@ -1,47 +1,53 @@
<template> <template>
<div class="mk-post-form"> <div class="mk-post-form">
<header>
<button class="cancel" @click="cancel">%fa:times%</button>
<div>
<span class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</span>
<span class="geo" v-if="geo">%fa:map-marker-alt%</span>
<button class="submit" :disabled="!canPost" @click="post">{{ submitText }}</button>
</div>
</header>
<div class="form"> <div class="form">
<mk-note-preview v-if="reply" :note="reply"/> <header>
<mk-note-preview v-if="renote" :note="renote"/> <button class="cancel" @click="cancel">%fa:times%</button>
<div v-if="visibility == 'specified'" class="visibleUsers"> <div>
<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span> <span class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</span>
<a @click="addVisibleUser">+%i18n:@add-visible-user%</a> <span class="geo" v-if="geo">%fa:map-marker-alt%</span>
<button class="submit" :disabled="!canPost" @click="post">{{ submitText }}</button>
</div>
</header>
<div class="form">
<mk-note-preview v-if="reply" :note="reply"/>
<mk-note-preview v-if="renote" :note="renote"/>
<div v-if="visibility == 'specified'" class="visibleUsers">
<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
<a @click="addVisibleUser">+%i18n:@add-visible-user%</a>
</div>
<input v-show="useCw" v-model="cw" placeholder="%i18n:@cw-placeholder%">
<textarea v-model="text" ref="text" :disabled="posting" :placeholder="placeholder" v-autocomplete="'text'"></textarea>
<div class="attaches" v-show="files.length != 0">
<x-draggable class="files" :list="files" :options="{ animation: 150 }">
<div class="file" v-for="file in files" :key="file.id">
<div class="img" :style="`background-image: url(${file.url}?thumbnail&size=128)`" @click="detachMedia(file)"></div>
</div>
</x-draggable>
</div>
<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false"/>
<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
<footer>
<button class="upload" @click="chooseFile">%fa:upload%</button>
<button class="drive" @click="chooseFileFromDrive">%fa:cloud%</button>
<button class="kao" @click="kao">%fa:R smile%</button>
<button class="poll" @click="poll = true">%fa:chart-pie%</button>
<button class="poll" @click="useCw = !useCw">%fa:eye-slash%</button>
<button class="geo" @click="geo ? removeGeo() : setGeo()">%fa:map-marker-alt%</button>
<button class="visibility" @click="setVisibility" ref="visibilityButton">%fa:lock%</button>
</footer>
<input ref="file" class="file" type="file" accept="image/*" multiple="multiple" @change="onChangeFile"/>
</div> </div>
<input v-show="useCw" v-model="cw" placeholder="%i18n:@cw-placeholder%"> </div>
<textarea v-model="text" ref="text" :disabled="posting" :placeholder="placeholder" v-autocomplete="'text'"></textarea> <div class="hashtags" v-if="recentHashtags.length > 0">
<div class="attaches" v-show="files.length != 0"> <a v-for="tag in recentHashtags" @click="addTag(tag)">#{{ tag }}</a>
<x-draggable class="files" :list="files" :options="{ animation: 150 }">
<div class="file" v-for="file in files" :key="file.id">
<div class="img" :style="`background-image: url(${file.url}?thumbnail&size=128)`" @click="detachMedia(file)"></div>
</div>
</x-draggable>
</div>
<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false"/>
<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
<footer>
<button class="upload" @click="chooseFile">%fa:upload%</button>
<button class="drive" @click="chooseFileFromDrive">%fa:cloud%</button>
<button class="kao" @click="kao">%fa:R smile%</button>
<button class="poll" @click="poll = true">%fa:chart-pie%</button>
<button class="poll" @click="useCw = !useCw">%fa:eye-slash%</button>
<button class="geo" @click="geo ? removeGeo() : setGeo()">%fa:map-marker-alt%</button>
<button class="visibility" @click="setVisibility" ref="visibilityButton">%fa:lock%</button>
</footer>
<input ref="file" class="file" type="file" accept="image/*" multiple="multiple" @change="onChangeFile"/>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import insertTextAtCursor from 'insert-text-at-cursor';
import * as XDraggable from 'vuedraggable'; import * as XDraggable from 'vuedraggable';
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue'; import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
import getKao from '../../../common/scripts/get-kao'; import getKao from '../../../common/scripts/get-kao';
@ -85,7 +91,8 @@ export default Vue.extend({
visibility: 'public', visibility: 'public',
visibleUsers: [], visibleUsers: [],
useCw: false, useCw: false,
cw: null cw: null,
recentHashtags: JSON.parse(localStorage.getItem('hashtags') || '[]')
}; };
}, },
@ -161,6 +168,10 @@ export default Vue.extend({
}, },
methods: { methods: {
addTag(tag: string) {
insertTextAtCursor(this.$refs.text, ` #${tag} `);
},
focus() { focus() {
(this.$refs.text as any).focus(); (this.$refs.text as any).focus();
}, },
@ -281,6 +292,13 @@ export default Vue.extend({
}).catch(err => { }).catch(err => {
this.posting = false; this.posting = false;
}); });
if (this.text && this.text != '') {
const hashtags = parse(this.text).filter(x => x.type == 'hashtag').map(x => x.hashtag);
let history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
history = history.filter(x => !hashtags.includes(x));
localStorage.setItem('hashtags', JSON.stringify(hashtags.concat(history)));
}
}, },
cancel() { cancel() {
@ -302,146 +320,156 @@ root(isDark)
max-width 500px max-width 500px
width calc(100% - 16px) width calc(100% - 16px)
margin 8px auto margin 8px auto
background isDark ? #282C37 : #fff
border-radius 8px
box-shadow 0 0 2px rgba(#000, 0.1)
@media (min-width 500px) @media (min-width 500px)
margin 16px auto margin 16px auto
width calc(100% - 32px) width calc(100% - 32px)
box-shadow 0 8px 32px rgba(#000, 0.1)
> .form
box-shadow 0 8px 32px rgba(#000, 0.1)
@media (min-width 600px) @media (min-width 600px)
margin 32px auto margin 32px auto
> header
z-index 1000
height 50px
box-shadow 0 1px 0 0 isDark ? rgba(#000, 0.2) : rgba(#000, 0.1)
> .cancel
padding 0
width 50px
line-height 50px
font-size 24px
color isDark ? #9baec8 : #555
> div
position absolute
top 0
right 0
color #657786
> .text-count
line-height 50px
> .geo
margin 0 8px
line-height 50px
> .submit
margin 8px
padding 0 16px
line-height 34px
vertical-align bottom
color $theme-color-foreground
background $theme-color
border-radius 4px
&:disabled
opacity 0.7
> .form > .form
max-width 500px background isDark ? #282C37 : #fff
margin 0 auto border-radius 8px
box-shadow 0 0 2px rgba(#000, 0.1)
> .mk-note-preview > header
padding 16px z-index 1000
height 50px
> .visibleUsers
margin-bottom 8px
font-size 14px
> span
margin-right 16px
color isDark ? #fff : #666
> input
z-index 1
> input
> textarea
display block
padding 12px
margin 0
width 100%
font-size 16px
color isDark ? #fff : #333
background isDark ? #191d23 : #fff
border none
border-radius 0
box-shadow 0 1px 0 0 isDark ? rgba(#000, 0.2) : rgba(#000, 0.1) box-shadow 0 1px 0 0 isDark ? rgba(#000, 0.2) : rgba(#000, 0.1)
&:disabled > .cancel
opacity 0.5
> textarea
max-width 100%
min-width 100%
min-height 80px
> .attaches
> .files
display block
margin 0
padding 4px
list-style none
&:after
content ""
display block
clear both
> .file
display block
float left
margin 0
padding 0
border solid 4px transparent
> .img
width 64px
height 64px
background-size cover
background-position center center
> .mk-uploader
margin 8px 0 0 0
padding 8px
> .file
display none
> footer
white-space nowrap
overflow auto
-webkit-overflow-scrolling touch
overflow-scrolling touch
> *
display inline-block
padding 0 padding 0
margin 0 width 50px
width 48px line-height 50px
height 48px font-size 24px
font-size 20px color isDark ? #9baec8 : #555
> div
position absolute
top 0
right 0
color #657786 color #657786
background transparent
outline none > .text-count
line-height 50px
> .geo
margin 0 8px
line-height 50px
> .submit
margin 8px
padding 0 16px
line-height 34px
vertical-align bottom
color $theme-color-foreground
background $theme-color
border-radius 4px
&:disabled
opacity 0.7
> .form
max-width 500px
margin 0 auto
> .mk-note-preview
padding 16px
> .visibleUsers
margin-bottom 8px
font-size 14px
> span
margin-right 16px
color isDark ? #fff : #666
> input
z-index 1
> input
> textarea
display block
padding 12px
margin 0
width 100%
font-size 16px
color isDark ? #fff : #333
background isDark ? #191d23 : #fff
border none border none
border-radius 0 border-radius 0
box-shadow none box-shadow 0 1px 0 0 isDark ? rgba(#000, 0.2) : rgba(#000, 0.1)
&:disabled
opacity 0.5
> textarea
max-width 100%
min-width 100%
min-height 80px
> .attaches
> .files
display block
margin 0
padding 4px
list-style none
&:after
content ""
display block
clear both
> .file
display block
float left
margin 0
padding 0
border solid 4px transparent
> .img
width 64px
height 64px
background-size cover
background-position center center
> .mk-uploader
margin 8px 0 0 0
padding 8px
> .file
display none
> footer
white-space nowrap
overflow auto
-webkit-overflow-scrolling touch
overflow-scrolling touch
> *
display inline-block
padding 0
margin 0
width 48px
height 48px
font-size 20px
color #657786
background transparent
outline none
border none
border-radius 0
box-shadow none
> .hashtags
margin 8px
> *
margin-right 8px
.mk-post-form[data-darkmode] .mk-post-form[data-darkmode]
root(true) root(true)