summaryrefslogtreecommitdiff
path: root/src/client/components
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-05-31 13:06:40 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-05-31 13:06:40 +0900
commit929e5455149fd770c53dc03dabd9572f586772c1 (patch)
treec34d7f85b0a7b324f412b2a6bb4168574da30f6f /src/client/components
parentMerge branch 'develop' (diff)
parent12.82.0 (diff)
downloadmisskey-929e5455149fd770c53dc03dabd9572f586772c1.tar.gz
misskey-929e5455149fd770c53dc03dabd9572f586772c1.tar.bz2
misskey-929e5455149fd770c53dc03dabd9572f586772c1.zip
Merge branch 'develop'
Diffstat (limited to 'src/client/components')
-rw-r--r--src/client/components/date-separated-list.vue4
-rw-r--r--src/client/components/drive.file.vue24
-rw-r--r--src/client/components/drive.vue4
-rw-r--r--src/client/components/follow-button.vue2
-rw-r--r--src/client/components/image-viewer.vue2
-rw-r--r--src/client/components/media-caption.vue238
-rw-r--r--src/client/components/media-image.vue4
-rw-r--r--src/client/components/notification.vue2
-rw-r--r--src/client/components/notifications.vue8
-rw-r--r--src/client/components/post-form-attaches.vue25
-rw-r--r--src/client/components/timeline.vue20
11 files changed, 311 insertions, 22 deletions
diff --git a/src/client/components/date-separated-list.vue b/src/client/components/date-separated-list.vue
index 34085cc070..6a0c7f29f2 100644
--- a/src/client/components/date-separated-list.vue
+++ b/src/client/components/date-separated-list.vue
@@ -1,11 +1,11 @@
<script lang="ts">
-import { defineComponent, h, TransitionGroup } from 'vue';
+import { defineComponent, h, PropType, TransitionGroup } from 'vue';
import MkAd from '@client/components/global/ad.vue';
export default defineComponent({
props: {
items: {
- type: Array,
+ type: Array as PropType<{ id: string; createdAt: string; _shouldInsertAd_: boolean; }[]>,
required: true,
},
direction: {
diff --git a/src/client/components/drive.file.vue b/src/client/components/drive.file.vue
index 37b1afc1b3..3d20de23e9 100644
--- a/src/client/components/drive.file.vue
+++ b/src/client/components/drive.file.vue
@@ -87,6 +87,10 @@ export default defineComponent({
text: this.file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive,
icon: this.file.isSensitive ? 'fas fa-eye' : 'fas fa-eye-slash',
action: this.toggleSensitive
+ }, {
+ text: this.$ts.describeFile,
+ icon: 'fas fa-i-cursor',
+ action: this.describe
}, null, {
text: this.$ts.copyUrl,
icon: 'fas fa-link',
@@ -150,6 +154,26 @@ export default defineComponent({
});
},
+ describe() {
+ os.popup(import('@client/components/media-caption.vue'), {
+ title: this.$ts.describeFile,
+ input: {
+ placeholder: this.$ts.inputNewDescription,
+ default: this.file.comment !== null ? this.file.comment : '',
+ },
+ image: this.file
+ }, {
+ done: result => {
+ if (!result || result.canceled) return;
+ let comment = result.result;
+ os.api('drive/files/update', {
+ fileId: this.file.id,
+ comment: comment.length == 0 ? null : comment
+ });
+ }
+ }, 'closed');
+ },
+
toggleSensitive() {
os.api('drive/files/update', {
fileId: this.file.id,
diff --git a/src/client/components/drive.vue b/src/client/components/drive.vue
index 06f9cf7806..ca637e3f3d 100644
--- a/src/client/components/drive.vue
+++ b/src/client/components/drive.vue
@@ -139,7 +139,7 @@ export default defineComponent({
});
}
- this.connection = os.stream.useSharedConnection('drive');
+ this.connection = os.stream.useChannel('drive');
this.connection.on('fileCreated', this.onStreamDriveFileCreated);
this.connection.on('fileUpdated', this.onStreamDriveFileUpdated);
@@ -301,7 +301,7 @@ export default defineComponent({
}
}).then(({ canceled, result: url }) => {
if (canceled) return;
- os.api('drive/files/upload_from_url', {
+ os.api('drive/files/upload-from-url', {
url: url,
folderId: this.folder ? this.folder.id : undefined
});
diff --git a/src/client/components/follow-button.vue b/src/client/components/follow-button.vue
index 7199183c66..49bf678491 100644
--- a/src/client/components/follow-button.vue
+++ b/src/client/components/follow-button.vue
@@ -71,7 +71,7 @@ export default defineComponent({
},
mounted() {
- this.connection = os.stream.useSharedConnection('main');
+ this.connection = os.stream.useChannel('main');
this.connection.on('follow', this.onFollowChange);
this.connection.on('unfollow', this.onFollowChange);
diff --git a/src/client/components/image-viewer.vue b/src/client/components/image-viewer.vue
index ec22bd98ec..7701ae926f 100644
--- a/src/client/components/image-viewer.vue
+++ b/src/client/components/image-viewer.vue
@@ -2,7 +2,7 @@
<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="xubzgfga">
<header>{{ image.name }}</header>
- <img :src="image.url" :alt="image.name" :title="image.name" @click="$refs.modal.close()"/>
+ <img :src="image.url" :alt="image.comment" :title="image.comment" @click="$refs.modal.close()"/>
<footer>
<span>{{ image.type }}</span>
<span>{{ bytes(image.size) }}</span>
diff --git a/src/client/components/media-caption.vue b/src/client/components/media-caption.vue
new file mode 100644
index 0000000000..690927d4c5
--- /dev/null
+++ b/src/client/components/media-caption.vue
@@ -0,0 +1,238 @@
+<template>
+ <MkModal ref="modal" @click="done(true)" @closed="$emit('closed')">
+ <div class="container">
+ <div class="fullwidth top-caption">
+ <div class="mk-dialog">
+ <header v-if="title"><Mfm :text="title"/></header>
+ <textarea autofocus v-model="inputValue" :placeholder="input.placeholder" @keydown="onInputKeydown"></textarea>
+ <div class="buttons" v-if="(showOkButton || showCancelButton)">
+ <MkButton inline @click="ok" primary>{{ $ts.ok }}</MkButton>
+ <MkButton inline @click="cancel" >{{ $ts.cancel }}</MkButton>
+ </div>
+ </div>
+ </div>
+ <div class="hdrwpsaf fullwidth">
+ <header>{{ image.name }}</header>
+ <img :src="image.url" :alt="image.comment" :title="image.comment" @click="$refs.modal.close()"/>
+ <footer>
+ <span>{{ image.type }}</span>
+ <span>{{ bytes(image.size) }}</span>
+ <span v-if="image.properties && image.properties.width">{{ number(image.properties.width) }}px × {{ number(image.properties.height) }}px</span>
+ </footer>
+ </div>
+ </div>
+ </MkModal>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import MkModal from '@client/components/ui/modal.vue';
+import MkButton from '@client/components/ui/button.vue';
+import bytes from '@client/filters/bytes';
+import number from '@client/filters/number';
+
+export default defineComponent({
+ components: {
+ MkModal,
+ MkButton,
+ },
+
+ props: {
+ image: {
+ type: Object,
+ required: true,
+ },
+ title: {
+ type: String,
+ required: false
+ },
+ input: {
+ required: true
+ },
+ showOkButton: {
+ type: Boolean,
+ default: true
+ },
+ showCancelButton: {
+ type: Boolean,
+ default: true
+ },
+ cancelableByBgClick: {
+ type: Boolean,
+ default: true
+ },
+ },
+
+ emits: ['done', 'closed'],
+
+ data() {
+ return {
+ inputValue: this.input.default ? this.input.default : null
+ };
+ },
+
+ mounted() {
+ document.addEventListener('keydown', this.onKeydown);
+ },
+
+ beforeUnmount() {
+ document.removeEventListener('keydown', this.onKeydown);
+ },
+
+ methods: {
+ bytes,
+ number,
+
+ done(canceled, result?) {
+ this.$emit('done', { canceled, result });
+ this.$refs.modal.close();
+ },
+
+ async ok() {
+ if (!this.showOkButton) return;
+
+ const result = this.inputValue;
+ this.done(false, result);
+ },
+
+ cancel() {
+ this.done(true);
+ },
+
+ onBgClick() {
+ if (this.cancelableByBgClick) {
+ this.cancel();
+ }
+ },
+
+ onKeydown(e) {
+ if (e.which === 27) { // ESC
+ this.cancel();
+ }
+ },
+
+ onInputKeydown(e) {
+ if (e.which === 13) { // Enter
+ if (e.ctrlKey) {
+ e.preventDefault();
+ e.stopPropagation();
+ this.ok();
+ }
+ }
+ }
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+.container {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ flex-direction: row;
+}
+@media (max-width: 850px) {
+ .container {
+ flex-direction: column;
+ }
+ .top-caption {
+ padding-bottom: 8px;
+ }
+}
+.fullwidth {
+ width: 100%;
+ margin: auto;
+}
+.mk-dialog {
+ position: relative;
+ padding: 32px;
+ min-width: 320px;
+ max-width: 480px;
+ box-sizing: border-box;
+ text-align: center;
+ background: var(--panel);
+ border-radius: var(--radius);
+ margin: auto;
+
+ > header {
+ margin: 0 0 8px 0;
+ font-weight: bold;
+ font-size: 20px;
+ }
+
+ > .buttons {
+ margin-top: 16px;
+
+ > * {
+ margin: 0 8px;
+ }
+ }
+
+ > textarea {
+ display: block;
+ box-sizing: border-box;
+ padding: 0 24px;
+ margin: 0;
+ width: 100%;
+ font-size: 16px;
+ border: none;
+ border-radius: 0;
+ background: transparent;
+ color: var(--fg);
+ font-family: inherit;
+ max-width: 100%;
+ min-width: 100%;
+ min-height: 90px;
+
+ &:focus {
+ outline: none;
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ }
+ }
+}
+.hdrwpsaf {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+
+ > header,
+ > footer {
+ align-self: center;
+ display: inline-block;
+ padding: 6px 9px;
+ font-size: 90%;
+ background: rgba(0, 0, 0, 0.5);
+ border-radius: 6px;
+ color: #fff;
+ }
+
+ > header {
+ margin-bottom: 8px;
+ opacity: 0.9;
+ }
+
+ > img {
+ display: block;
+ flex: 1;
+ min-height: 0;
+ object-fit: contain;
+ width: 100%;
+ cursor: zoom-out;
+ image-orientation: from-image;
+ }
+
+ > footer {
+ margin-top: 8px;
+ opacity: 0.8;
+
+ > span + span {
+ margin-left: 0.5em;
+ padding-left: 0.5em;
+ border-left: solid 1px rgba(255, 255, 255, 0.5);
+ }
+ }
+}
+</style>
diff --git a/src/client/components/media-image.vue b/src/client/components/media-image.vue
index 267e4debd2..863eb10272 100644
--- a/src/client/components/media-image.vue
+++ b/src/client/components/media-image.vue
@@ -1,6 +1,6 @@
<template>
<div class="qjewsnkg" v-if="hide" @click="hide = false">
- <ImgWithBlurhash class="bg" :hash="image.blurhash" :title="image.name"/>
+ <ImgWithBlurhash class="bg" :hash="image.blurhash" :title="image.comment" :alt="image.comment"/>
<div class="text">
<div>
<b><i class="fas fa-exclamation-triangle"></i> {{ $ts.sensitive }}</b>
@@ -14,7 +14,7 @@
:title="image.name"
@click.prevent="onClick"
>
- <ImgWithBlurhash :hash="image.blurhash" :src="url" :alt="image.name" :title="image.name" :cover="false"/>
+ <ImgWithBlurhash :hash="image.blurhash" :src="url" :alt="image.comment" :title="image.comment" :cover="false"/>
<div class="gif" v-if="image.type === 'image/gif'">GIF</div>
</a>
<i class="fas fa-eye-slash" @click="hide = true"></i>
diff --git a/src/client/components/notification.vue b/src/client/components/notification.vue
index 9badd7a708..c7063b0aa2 100644
--- a/src/client/components/notification.vue
+++ b/src/client/components/notification.vue
@@ -109,7 +109,7 @@ export default defineComponent({
this.readObserver.observe(this.$el);
- this.connection = os.stream.useSharedConnection('main');
+ this.connection = os.stream.useChannel('main');
this.connection.on('readAllNotifications', () => this.readObserver.unobserve(this.$el));
}
},
diff --git a/src/client/components/notifications.vue b/src/client/components/notifications.vue
index 161419f891..092c00f14e 100644
--- a/src/client/components/notifications.vue
+++ b/src/client/components/notifications.vue
@@ -12,10 +12,10 @@
<XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/>
</XList>
- <button class="_buttonPrimary" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
+ <MkButton primary style="margin: var(--margin) auto;" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
<template v-if="moreFetching"><MkLoading inline/></template>
- </button>
+ </MkButton>
</div>
</transition>
</template>
@@ -28,12 +28,14 @@ import XList from './date-separated-list.vue';
import XNote from './note.vue';
import { notificationTypes } from '../../types';
import * as os from '@client/os';
+import MkButton from '@client/components/ui/button.vue';
export default defineComponent({
components: {
XNotification,
XList,
XNote,
+ MkButton,
},
mixins: [
@@ -87,7 +89,7 @@ export default defineComponent({
},
mounted() {
- this.connection = os.stream.useSharedConnection('main');
+ this.connection = os.stream.useChannel('main');
this.connection.on('notification', this.onNotification);
},
diff --git a/src/client/components/post-form-attaches.vue b/src/client/components/post-form-attaches.vue
index f832ea87b5..27e20fdfa8 100644
--- a/src/client/components/post-form-attaches.vue
+++ b/src/client/components/post-form-attaches.vue
@@ -89,6 +89,27 @@ export default defineComponent({
file.name = result;
});
},
+
+ async describe(file) {
+ os.popup(import("@client/components/media-caption.vue"), {
+ title: this.$ts.describeFile,
+ input: {
+ placeholder: this.$ts.inputNewDescription,
+ default: file.comment !== null ? file.comment : "",
+ },
+ image: file
+ }, {
+ done: result => {
+ if (!result || result.canceled) return;
+ let comment = result.result;
+ os.api('drive/files/update', {
+ fileId: file.id,
+ comment: comment.length == 0 ? null : comment
+ });
+ }
+ }, 'closed');
+ },
+
showFileMenu(file, ev: MouseEvent) {
if (this.menu) return;
this.menu = os.modalMenu([{
@@ -100,6 +121,10 @@ export default defineComponent({
icon: file.isSensitive ? 'fas fa-eye-slash' : 'fas fa-eye',
action: () => { this.toggleSensitive(file) }
}, {
+ text: this.$ts.describeFile,
+ icon: 'fas fa-i-cursor',
+ action: () => { this.describe(file) }
+ }, {
text: this.$ts.attachCancel,
icon: 'fas fa-times-circle',
action: () => { this.detachMedia(file.id) }
diff --git a/src/client/components/timeline.vue b/src/client/components/timeline.vue
index 753eba2ba1..c21e1ec2a6 100644
--- a/src/client/components/timeline.vue
+++ b/src/client/components/timeline.vue
@@ -92,33 +92,33 @@ export default defineComponent({
this.query = {
antennaId: this.antenna
};
- this.connection = os.stream.connectToChannel('antenna', {
+ this.connection = os.stream.useChannel('antenna', {
antennaId: this.antenna
});
this.connection.on('note', prepend);
} else if (this.src == 'home') {
endpoint = 'notes/timeline';
- this.connection = os.stream.useSharedConnection('homeTimeline');
+ this.connection = os.stream.useChannel('homeTimeline');
this.connection.on('note', prepend);
- this.connection2 = os.stream.useSharedConnection('main');
+ this.connection2 = os.stream.useChannel('main');
this.connection2.on('follow', onChangeFollowing);
this.connection2.on('unfollow', onChangeFollowing);
} else if (this.src == 'local') {
endpoint = 'notes/local-timeline';
- this.connection = os.stream.useSharedConnection('localTimeline');
+ this.connection = os.stream.useChannel('localTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'social') {
endpoint = 'notes/hybrid-timeline';
- this.connection = os.stream.useSharedConnection('hybridTimeline');
+ this.connection = os.stream.useChannel('hybridTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'global') {
endpoint = 'notes/global-timeline';
- this.connection = os.stream.useSharedConnection('globalTimeline');
+ this.connection = os.stream.useChannel('globalTimeline');
this.connection.on('note', prepend);
} else if (this.src == 'mentions') {
endpoint = 'notes/mentions';
- this.connection = os.stream.useSharedConnection('main');
+ this.connection = os.stream.useChannel('main');
this.connection.on('mention', prepend);
} else if (this.src == 'directs') {
endpoint = 'notes/mentions';
@@ -130,14 +130,14 @@ export default defineComponent({
prepend(note);
}
};
- this.connection = os.stream.useSharedConnection('main');
+ this.connection = os.stream.useChannel('main');
this.connection.on('mention', onNote);
} else if (this.src == 'list') {
endpoint = 'notes/user-list-timeline';
this.query = {
listId: this.list
};
- this.connection = os.stream.connectToChannel('userList', {
+ this.connection = os.stream.useChannel('userList', {
listId: this.list
});
this.connection.on('note', prepend);
@@ -148,7 +148,7 @@ export default defineComponent({
this.query = {
channelId: this.channel
};
- this.connection = os.stream.connectToChannel('channel', {
+ this.connection = os.stream.useChannel('channel', {
channelId: this.channel
});
this.connection.on('note', prepend);