Merge branch 'develop' into improve-media
This commit is contained in:
@ -78,7 +78,7 @@ export default Vue.extend({
|
||||
scale: 0.8,
|
||||
duration: 300,
|
||||
easing: [ 0.5, -0.5, 1, 0.5 ],
|
||||
complete: () => this.$destroy()
|
||||
complete: () => this.destroyDom()
|
||||
});
|
||||
},
|
||||
onBgClick() {
|
||||
|
@ -31,15 +31,15 @@ export default Vue.extend({
|
||||
},
|
||||
onSelected(file) {
|
||||
this.$emit('selected', file);
|
||||
this.$destroy();
|
||||
this.destroyDom();
|
||||
},
|
||||
cancel() {
|
||||
this.$emit('canceled');
|
||||
this.$destroy();
|
||||
this.destroyDom();
|
||||
},
|
||||
ok() {
|
||||
this.$emit('selected', this.files);
|
||||
this.$destroy();
|
||||
this.destroyDom();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -19,11 +19,11 @@ export default Vue.extend({
|
||||
methods: {
|
||||
cancel() {
|
||||
this.$emit('canceled');
|
||||
this.$destroy();
|
||||
this.destroyDom();
|
||||
},
|
||||
ok() {
|
||||
this.$emit('selected', (this.$refs.browser as any).folder);
|
||||
this.$destroy();
|
||||
this.destroyDom();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -67,7 +67,7 @@
|
||||
import Vue from 'vue';
|
||||
import * as EXIF from 'exif-js';
|
||||
import * as hljs from 'highlight.js';
|
||||
import gcd from '../../../common/scripts/gcd';
|
||||
import { gcd } from '../../../../../prelude/math';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['file'],
|
||||
|
@ -47,7 +47,7 @@ export default Vue.extend({
|
||||
this.fetch();
|
||||
},
|
||||
close() {
|
||||
this.$destroy();
|
||||
this.destroyDom();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="qjewsnkgzzxlxtzncydssfbgjibiehcy" v-if="image.isSensitive && hide" @click="hide = false">
|
||||
<div class="qjewsnkgzzxlxtzncydssfbgjibiehcy" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false">
|
||||
<div>
|
||||
<b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
|
||||
<span>%i18n:@click-to-show%</span>
|
||||
|
@ -35,20 +35,26 @@
|
||||
</div>
|
||||
</header>
|
||||
<div class="body">
|
||||
<div class="text">
|
||||
<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
||||
<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
|
||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
|
||||
</div>
|
||||
<div class="media" v-if="p.media.length > 0">
|
||||
<mk-media-list :media-list="p.media" :raw="true"/>
|
||||
</div>
|
||||
<mk-poll v-if="p.poll" :note="p"/>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
|
||||
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
|
||||
<div class="map" v-if="p.geo" ref="map"></div>
|
||||
<div class="renote" v-if="p.renote">
|
||||
<mk-note-preview :note="p.renote"/>
|
||||
<p v-if="p.cw != null" class="cw">
|
||||
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
||||
<mk-cw-button v-model="showContent"/>
|
||||
</p>
|
||||
<div class="content" v-show="p.cw == null || showContent">
|
||||
<div class="text">
|
||||
<span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
||||
<span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span>
|
||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
|
||||
</div>
|
||||
<div class="files" v-if="p.files.length > 0">
|
||||
<mk-media-list :media-list="p.files" :raw="true"/>
|
||||
</div>
|
||||
<mk-poll v-if="p.poll" :note="p"/>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
|
||||
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
|
||||
<div class="map" v-if="p.geo" ref="map"></div>
|
||||
<div class="renote" v-if="p.renote">
|
||||
<mk-note-preview :note="p.renote"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<router-link class="time" :to="p | notePage">
|
||||
@ -85,6 +91,7 @@ import parse from '../../../../../mfm/parse';
|
||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
|
||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
|
||||
import XSub from './note.sub.vue';
|
||||
import { sum } from '../../../../../prelude/array';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
@ -103,6 +110,7 @@ export default Vue.extend({
|
||||
|
||||
data() {
|
||||
return {
|
||||
showContent: false,
|
||||
conversation: [],
|
||||
conversationFetching: false,
|
||||
replies: []
|
||||
@ -113,7 +121,7 @@ export default Vue.extend({
|
||||
isRenote(): boolean {
|
||||
return (this.note.renote &&
|
||||
this.note.text == null &&
|
||||
this.note.mediaIds.length == 0 &&
|
||||
this.note.fileIds.length == 0 &&
|
||||
this.note.poll == null);
|
||||
},
|
||||
|
||||
@ -123,9 +131,7 @@ export default Vue.extend({
|
||||
|
||||
reactionsCount(): number {
|
||||
return this.p.reactionCounts
|
||||
? Object.keys(this.p.reactionCounts)
|
||||
.map(key => this.p.reactionCounts[key])
|
||||
.reduce((a, b) => a + b)
|
||||
? sum(Object.values(this.p.reactionCounts))
|
||||
: 0;
|
||||
},
|
||||
|
||||
@ -335,44 +341,57 @@ root(isDark)
|
||||
> .body
|
||||
padding 8px 0
|
||||
|
||||
> .text
|
||||
> .cw
|
||||
cursor default
|
||||
display block
|
||||
margin 0
|
||||
padding 0
|
||||
overflow-wrap break-word
|
||||
font-size 16px
|
||||
color isDark ? #fff : #717171
|
||||
|
||||
@media (min-width 500px)
|
||||
font-size 24px
|
||||
> .text
|
||||
margin-right 8px
|
||||
|
||||
> .renote
|
||||
margin 8px 0
|
||||
> .content
|
||||
|
||||
> .mk-note-preview
|
||||
padding 16px
|
||||
border dashed 1px #c0dac6
|
||||
border-radius 8px
|
||||
|
||||
> .location
|
||||
margin 4px 0
|
||||
font-size 12px
|
||||
color #ccc
|
||||
|
||||
> .map
|
||||
width 100%
|
||||
height 200px
|
||||
|
||||
&:empty
|
||||
display none
|
||||
|
||||
> .mk-url-preview
|
||||
margin-top 8px
|
||||
|
||||
> .media
|
||||
> img
|
||||
> .text
|
||||
display block
|
||||
max-width 100%
|
||||
margin 0
|
||||
padding 0
|
||||
overflow-wrap break-word
|
||||
font-size 16px
|
||||
color isDark ? #fff : #717171
|
||||
|
||||
@media (min-width 500px)
|
||||
font-size 24px
|
||||
|
||||
> .renote
|
||||
margin 8px 0
|
||||
|
||||
> *
|
||||
padding 16px
|
||||
border dashed 1px #c0dac6
|
||||
border-radius 8px
|
||||
|
||||
> .location
|
||||
margin 4px 0
|
||||
font-size 12px
|
||||
color #ccc
|
||||
|
||||
> .map
|
||||
width 100%
|
||||
height 200px
|
||||
|
||||
&:empty
|
||||
display none
|
||||
|
||||
> .mk-url-preview
|
||||
margin-top 8px
|
||||
|
||||
> .files
|
||||
> img
|
||||
display block
|
||||
max-width 100%
|
||||
|
||||
> .time
|
||||
font-size 16px
|
||||
|
@ -1,10 +1,16 @@
|
||||
<template>
|
||||
<div class="mk-note-preview" :class="{ smart: $store.state.device.postStyle == 'smart' }">
|
||||
<div class="yohlumlkhizgfkvvscwfcrcggkotpvry" :class="{ smart: $store.state.device.postStyle == 'smart' }">
|
||||
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
||||
<div class="main">
|
||||
<mk-note-header class="header" :note="note" :mini="true"/>
|
||||
<div class="body">
|
||||
<mk-sub-note-content class="text" :note="note"/>
|
||||
<p v-if="note.cw != null" class="cw">
|
||||
<span class="text" v-if="note.cw != ''">{{ note.cw }}</span>
|
||||
<mk-cw-button v-model="showContent"/>
|
||||
</p>
|
||||
<div class="content" v-show="note.cw == null || showContent">
|
||||
<mk-sub-note-content class="text" :note="note"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -14,7 +20,18 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['note']
|
||||
props: {
|
||||
note: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showContent: false
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -65,16 +82,28 @@ root(isDark)
|
||||
|
||||
> .body
|
||||
|
||||
> .text
|
||||
> .cw
|
||||
cursor default
|
||||
display block
|
||||
margin 0
|
||||
padding 0
|
||||
color isDark ? #959ba7 : #717171
|
||||
overflow-wrap break-word
|
||||
color isDark ? #fff : #717171
|
||||
|
||||
.mk-note-preview[data-darkmode]
|
||||
> .text
|
||||
margin-right 8px
|
||||
|
||||
> .content
|
||||
> .text
|
||||
cursor default
|
||||
margin 0
|
||||
padding 0
|
||||
color isDark ? #959ba7 : #717171
|
||||
|
||||
.yohlumlkhizgfkvvscwfcrcggkotpvry[data-darkmode]
|
||||
root(true)
|
||||
|
||||
.mk-note-preview:not([data-darkmode])
|
||||
.yohlumlkhizgfkvvscwfcrcggkotpvry:not([data-darkmode])
|
||||
root(false)
|
||||
|
||||
</style>
|
||||
|
@ -1,10 +1,16 @@
|
||||
<template>
|
||||
<div class="sub" :class="{ smart: $store.state.device.postStyle == 'smart' }">
|
||||
<div class="zlrxdaqttccpwhpaagdmkawtzklsccam" :class="{ smart: $store.state.device.postStyle == 'smart' }">
|
||||
<mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle != 'smart'"/>
|
||||
<div class="main">
|
||||
<mk-note-header class="header" :note="note" :mini="true"/>
|
||||
<div class="body">
|
||||
<mk-sub-note-content class="text" :note="note"/>
|
||||
<p v-if="note.cw != null" class="cw">
|
||||
<span class="text" v-if="note.cw != ''">{{ note.cw }}</span>
|
||||
<mk-cw-button v-model="showContent"/>
|
||||
</p>
|
||||
<div class="content" v-show="note.cw == null || showContent">
|
||||
<mk-sub-note-content class="text" :note="note"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -24,6 +30,12 @@ export default Vue.extend({
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showContent: false
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@ -77,20 +89,31 @@ root(isDark)
|
||||
margin-bottom 2px
|
||||
|
||||
> .body
|
||||
|
||||
> .text
|
||||
> .cw
|
||||
cursor default
|
||||
display block
|
||||
margin 0
|
||||
padding 0
|
||||
color isDark ? #959ba7 : #717171
|
||||
overflow-wrap break-word
|
||||
color isDark ? #fff : #717171
|
||||
|
||||
pre
|
||||
max-height 120px
|
||||
font-size 80%
|
||||
> .text
|
||||
margin-right 8px
|
||||
|
||||
.sub[data-darkmode]
|
||||
> .content
|
||||
> .text
|
||||
margin 0
|
||||
padding 0
|
||||
color isDark ? #959ba7 : #717171
|
||||
|
||||
pre
|
||||
max-height 120px
|
||||
font-size 80%
|
||||
|
||||
.zlrxdaqttccpwhpaagdmkawtzklsccam[data-darkmode]
|
||||
root(true)
|
||||
|
||||
.sub:not([data-darkmode])
|
||||
.zlrxdaqttccpwhpaagdmkawtzklsccam:not([data-darkmode])
|
||||
root(false)
|
||||
|
||||
</style>
|
||||
|
@ -18,7 +18,7 @@
|
||||
<div class="body">
|
||||
<p v-if="p.cw != null" class="cw">
|
||||
<span class="text" v-if="p.cw != ''">{{ p.cw }}</span>
|
||||
<span class="toggle" @click="showContent = !showContent">{{ showContent ? '%i18n:@less%' : '%i18n:@more%' }}</span>
|
||||
<mk-cw-button v-model="showContent"/>
|
||||
</p>
|
||||
<div class="content" v-show="p.cw == null || showContent">
|
||||
<div class="text">
|
||||
@ -28,16 +28,14 @@
|
||||
<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
|
||||
<a class="rp" v-if="p.renote != null">RP:</a>
|
||||
</div>
|
||||
<div class="media" v-if="p.media.length > 0">
|
||||
<mk-media-list :media-list="p.media"/>
|
||||
<div class="files" v-if="p.files.length > 0">
|
||||
<mk-media-list :media-list="p.files"/>
|
||||
</div>
|
||||
<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
||||
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
|
||||
<div class="map" v-if="p.geo" ref="map"></div>
|
||||
<div class="renote" v-if="p.renote">
|
||||
<mk-note-preview :note="p.renote"/>
|
||||
</div>
|
||||
<div class="renote" v-if="p.renote"><mk-note-preview :note="p.renote"/></div>
|
||||
</div>
|
||||
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
||||
</div>
|
||||
@ -70,6 +68,7 @@ import parse from '../../../../../mfm/parse';
|
||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
|
||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
|
||||
import XSub from './note.sub.vue';
|
||||
import { sum } from '../../../../../prelude/array';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
@ -90,7 +89,7 @@ export default Vue.extend({
|
||||
isRenote(): boolean {
|
||||
return (this.note.renote &&
|
||||
this.note.text == null &&
|
||||
this.note.mediaIds.length == 0 &&
|
||||
this.note.fileIds.length == 0 &&
|
||||
this.note.poll == null);
|
||||
},
|
||||
|
||||
@ -100,9 +99,7 @@ export default Vue.extend({
|
||||
|
||||
reactionsCount(): number {
|
||||
return this.p.reactionCounts
|
||||
? Object.keys(this.p.reactionCounts)
|
||||
.map(key => this.p.reactionCounts[key])
|
||||
.reduce((a, b) => a + b)
|
||||
? sum(Object.values(this.p.reactionCounts))
|
||||
: 0;
|
||||
},
|
||||
|
||||
@ -353,19 +350,6 @@ root(isDark)
|
||||
> .text
|
||||
margin-right 8px
|
||||
|
||||
> .toggle
|
||||
display inline-block
|
||||
padding 4px 8px
|
||||
font-size 0.7em
|
||||
color isDark ? #393f4f : #fff
|
||||
background isDark ? #687390 : #b1b9c1
|
||||
border-radius 2px
|
||||
cursor pointer
|
||||
user-select none
|
||||
|
||||
&:hover
|
||||
background isDark ? #707b97 : #bbc4ce
|
||||
|
||||
> .content
|
||||
|
||||
> .text
|
||||
@ -414,7 +398,7 @@ root(isDark)
|
||||
.mk-url-preview
|
||||
margin-top 8px
|
||||
|
||||
> .media
|
||||
> .files
|
||||
> img
|
||||
display block
|
||||
max-width 100%
|
||||
@ -437,7 +421,7 @@ root(isDark)
|
||||
> .renote
|
||||
margin 8px 0
|
||||
|
||||
> .mk-note-preview
|
||||
> *
|
||||
padding 16px
|
||||
border dashed 1px isDark ? #4e945e : #c0dac6
|
||||
border-radius 8px
|
||||
|
@ -14,8 +14,7 @@
|
||||
</div>
|
||||
|
||||
<!-- トランジションを有効にするとなぜかメモリリークする -->
|
||||
<!-- <transition-group name="mk-notes" class="transition"> -->
|
||||
<div class="transition">
|
||||
<transition-group name="mk-notes" class="transition" tag="div">
|
||||
<template v-for="(note, i) in _notes">
|
||||
<mk-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)"/>
|
||||
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
|
||||
@ -23,8 +22,7 @@
|
||||
<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
<!-- </transition-group> -->
|
||||
</transition-group>
|
||||
|
||||
<footer v-if="more">
|
||||
<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||
@ -125,7 +123,7 @@ export default Vue.extend({
|
||||
prepend(note, silent = false) {
|
||||
//#region 弾く
|
||||
const isMyNote = note.userId == this.$store.state.i.id;
|
||||
const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
|
||||
const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
|
||||
|
||||
if (this.$store.state.settings.showMyRenotes === false) {
|
||||
if (isMyNote && isPureRenote) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="mk-notify">
|
||||
<div class="mk-notify" :class="pos">
|
||||
<div>
|
||||
<mk-notification-preview :notification="notification"/>
|
||||
</div>
|
||||
@ -12,11 +12,16 @@ import * as anime from 'animejs';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['notification'],
|
||||
computed: {
|
||||
pos() {
|
||||
return this.$store.state.device.mobileNotificationPosition;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
anime({
|
||||
targets: this.$el,
|
||||
bottom: '0px',
|
||||
[this.pos]: '0px',
|
||||
duration: 500,
|
||||
easing: 'easeOutQuad'
|
||||
});
|
||||
@ -24,10 +29,10 @@ export default Vue.extend({
|
||||
setTimeout(() => {
|
||||
anime({
|
||||
targets: this.$el,
|
||||
bottom: `-${this.$el.offsetHeight}px`,
|
||||
[this.pos]: `-${this.$el.offsetHeight}px`,
|
||||
duration: 500,
|
||||
easing: 'easeOutQuad',
|
||||
complete: () => this.$destroy()
|
||||
complete: () => this.destroyDom()
|
||||
});
|
||||
}, 6000);
|
||||
});
|
||||
@ -40,8 +45,7 @@ export default Vue.extend({
|
||||
$height = 78px
|
||||
|
||||
position fixed
|
||||
z-index 1024
|
||||
bottom -($height)
|
||||
z-index 10000
|
||||
left 0
|
||||
right 0
|
||||
width 100%
|
||||
@ -52,6 +56,12 @@ export default Vue.extend({
|
||||
pointer-events none
|
||||
font-size 80%
|
||||
|
||||
&.bottom
|
||||
bottom -($height)
|
||||
|
||||
&.top
|
||||
top -($height)
|
||||
|
||||
> div
|
||||
height 100%
|
||||
-webkit-backdrop-filter blur(2px)
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="ulveipglmagnxfgvitaxyszerjwiqmwl">
|
||||
<div class="bg" ref="bg" @click="onBgClick"></div>
|
||||
<div class="main" ref="main" @click.self="onBgClick">
|
||||
<div class="bg" ref="bg"></div>
|
||||
<div class="main" ref="main">
|
||||
<mk-post-form ref="form"
|
||||
:reply="reply"
|
||||
:renote="renote"
|
||||
@ -79,15 +79,10 @@ export default Vue.extend({
|
||||
translateY: 16,
|
||||
duration: 300,
|
||||
easing: 'easeOutQuad',
|
||||
complete: () => this.$destroy()
|
||||
complete: () => this.destroyDom()
|
||||
});
|
||||
},
|
||||
|
||||
onBgClick() {
|
||||
this.$emit('cancel');
|
||||
this.close();
|
||||
},
|
||||
|
||||
onPosted() {
|
||||
this.$emit('posted');
|
||||
this.close();
|
||||
|
@ -4,14 +4,14 @@
|
||||
<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="text-count" :class="{ over: trimmedLength(text) > 1000 }">{{ 1000 - trimmedLength(text) }}</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">
|
||||
<mk-note-preview v-if="reply" :note="reply"/>
|
||||
<mk-note-preview v-if="renote" :note="renote"/>
|
||||
<mk-note-preview class="preview" v-if="reply" :note="reply"/>
|
||||
<mk-note-preview class="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>
|
||||
@ -59,6 +59,9 @@ import MkVisibilityChooser from '../../../common/views/components/visibility-cho
|
||||
import getFace from '../../../common/scripts/get-face';
|
||||
import parse from '../../../../../mfm/parse';
|
||||
import { host } from '../../../config';
|
||||
import { erase } from '../../../../../prelude/array';
|
||||
import { length } from 'stringz';
|
||||
import parseAcct from '../../../../../misc/acct/parse';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
@ -94,7 +97,7 @@ export default Vue.extend({
|
||||
files: [],
|
||||
poll: false,
|
||||
geo: null,
|
||||
visibility: this.$store.state.device.visibility || 'public',
|
||||
visibility: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility,
|
||||
visibleUsers: [],
|
||||
useCw: false,
|
||||
cw: null,
|
||||
@ -178,6 +181,10 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
methods: {
|
||||
trimmedLength(text: string) {
|
||||
return length(text.trim());
|
||||
},
|
||||
|
||||
addTag(tag: string) {
|
||||
insertTextAtCursor(this.$refs.text, ` #${tag} `);
|
||||
},
|
||||
@ -200,12 +207,12 @@ export default Vue.extend({
|
||||
|
||||
attachMedia(driveFile) {
|
||||
this.files.push(driveFile);
|
||||
this.$emit('change-attached-media', this.files);
|
||||
this.$emit('change-attached-files', this.files);
|
||||
},
|
||||
|
||||
detachMedia(file) {
|
||||
this.files = this.files.filter(x => x.id != file.id);
|
||||
this.$emit('change-attached-media', this.files);
|
||||
this.$emit('change-attached-files', this.files);
|
||||
},
|
||||
|
||||
onChangeFile() {
|
||||
@ -252,24 +259,23 @@ export default Vue.extend({
|
||||
addVisibleUser() {
|
||||
(this as any).apis.input({
|
||||
title: '%i18n:@username-prompt%'
|
||||
}).then(username => {
|
||||
(this as any).api('users/show', {
|
||||
username
|
||||
}).then(user => {
|
||||
}).then(acct => {
|
||||
if (acct.startsWith('@')) acct = acct.substr(1);
|
||||
(this as any).api('users/show', parseAcct(acct)).then(user => {
|
||||
this.visibleUsers.push(user);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
removeVisibleUser(user) {
|
||||
this.visibleUsers = this.visibleUsers.filter(u => u != user);
|
||||
this.visibleUsers = erase(user, this.visibleUsers);
|
||||
},
|
||||
|
||||
clear() {
|
||||
this.text = '';
|
||||
this.files = [];
|
||||
this.poll = false;
|
||||
this.$emit('change-attached-media');
|
||||
this.$emit('change-attached-files');
|
||||
},
|
||||
|
||||
post() {
|
||||
@ -277,7 +283,7 @@ export default Vue.extend({
|
||||
const viaMobile = this.$store.state.settings.disableViaMobile !== true;
|
||||
(this as any).api('notes/create', {
|
||||
text: this.text == '' ? undefined : this.text,
|
||||
mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
|
||||
fileIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
|
||||
replyId: this.reply ? this.reply.id : undefined,
|
||||
renoteId: this.renote ? this.renote.id : undefined,
|
||||
poll: this.poll ? (this.$refs.poll as any).get() : undefined,
|
||||
@ -302,7 +308,7 @@ export default Vue.extend({
|
||||
if (this.text && this.text != '') {
|
||||
const hashtags = parse(this.text).filter(x => x.type == 'hashtag').map(x => x.hashtag);
|
||||
const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
|
||||
localStorage.setItem('hashtags', JSON.stringify(hashtags.concat(history).reduce((a, c) => a.includes(c) ? a : [...a, c], [])));
|
||||
localStorage.setItem('hashtags', JSON.stringify(unique(hashtags.concat(history))));
|
||||
}
|
||||
},
|
||||
|
||||
@ -381,7 +387,7 @@ root(isDark)
|
||||
max-width 500px
|
||||
margin 0 auto
|
||||
|
||||
> .mk-note-preview
|
||||
> .preview
|
||||
padding 16px
|
||||
|
||||
> .visibleUsers
|
||||
|
@ -7,9 +7,9 @@
|
||||
<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
|
||||
<a class="rp" v-if="note.renoteId">RP: ...</a>
|
||||
</div>
|
||||
<details v-if="note.media.length > 0">
|
||||
<summary>({{ '%i18n:@media-count%'.replace('{}', note.media.length) }})</summary>
|
||||
<mk-media-list :media-list="note.media"/>
|
||||
<details v-if="note.files.length > 0">
|
||||
<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>
|
||||
<mk-media-list :media-list="note.files"/>
|
||||
</details>
|
||||
<details v-if="note.poll">
|
||||
<summary>%i18n:@poll%</summary>
|
||||
|
@ -34,6 +34,12 @@
|
||||
<li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>%i18n:@darkmode%</span></p></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="announcements" v-if="announcements && announcements.length > 0">
|
||||
<article v-for="announcement in announcements">
|
||||
<span v-html="announcement.title" class="title"></span>
|
||||
<div v-html="announcement.text"></div>
|
||||
</article>
|
||||
</div>
|
||||
<a :href="aboutUrl"><p class="about">%i18n:@about%</p></a>
|
||||
</div>
|
||||
</transition>
|
||||
@ -46,23 +52,32 @@ import { lang } from '../../../config';
|
||||
|
||||
export default Vue.extend({
|
||||
props: ['isOpen'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
hasGameInvitation: false,
|
||||
connection: null,
|
||||
connectionId: null,
|
||||
aboutUrl: `/docs/${lang}/about`
|
||||
aboutUrl: `/docs/${lang}/about`,
|
||||
announcements: []
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
hasUnreadNotification(): boolean {
|
||||
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadNotification;
|
||||
},
|
||||
|
||||
hasUnreadMessagingMessage(): boolean {
|
||||
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadMessagingMessage;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
(this as any).os.getMeta().then(meta => {
|
||||
this.announcements = meta.broadcasts;
|
||||
});
|
||||
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection = (this as any).os.stream.getConnection();
|
||||
this.connectionId = (this as any).os.stream.use();
|
||||
@ -71,6 +86,7 @@ export default Vue.extend({
|
||||
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection.off('reversi_invited', this.onReversiInvited);
|
||||
@ -78,18 +94,22 @@ export default Vue.extend({
|
||||
(this as any).os.stream.dispose(this.connectionId);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
search() {
|
||||
const query = window.prompt('%i18n:@search%');
|
||||
if (query == null || query == '') return;
|
||||
this.$router.push(`/search?q=${encodeURIComponent(query)}`);
|
||||
},
|
||||
|
||||
onReversiInvited() {
|
||||
this.hasGameInvitation = true;
|
||||
},
|
||||
|
||||
onReversiNoInvites() {
|
||||
this.hasGameInvitation = false;
|
||||
},
|
||||
|
||||
dark() {
|
||||
this.$store.commit('device/set', {
|
||||
key: 'darkmode',
|
||||
@ -204,6 +224,17 @@ root(isDark)
|
||||
color $color
|
||||
opacity 0.5
|
||||
|
||||
.announcements
|
||||
> article
|
||||
background isDark ? rgba(30, 129, 216, 0.2) : rgba(155, 196, 232, 0.2)
|
||||
color isDark ? #fff : #3f4967
|
||||
padding 16px
|
||||
margin 8px 0
|
||||
font-size 12px
|
||||
|
||||
> .title
|
||||
font-weight bold
|
||||
|
||||
.about
|
||||
margin 0 0 8px 0
|
||||
padding 1em 0
|
||||
|
@ -41,7 +41,7 @@ export default Vue.extend({
|
||||
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
||||
(this as any).api('users/notes', {
|
||||
userId: this.user.id,
|
||||
withMedia: this.withMedia,
|
||||
withFiles: this.withMedia,
|
||||
limit: fetchLimit + 1
|
||||
}).then(notes => {
|
||||
if (notes.length == fetchLimit + 1) {
|
||||
@ -62,7 +62,7 @@ export default Vue.extend({
|
||||
|
||||
const promise = (this as any).api('users/notes', {
|
||||
userId: this.user.id,
|
||||
withMedia: this.withMedia,
|
||||
withFiles: this.withMedia,
|
||||
limit: fetchLimit + 1,
|
||||
untilId: (this.$refs.timeline as any).tail().id
|
||||
});
|
||||
|
Reference in New Issue
Block a user