This commit is contained in:
syuilo 2020-02-16 22:15:49 +09:00
parent bcd7d1f007
commit dc39caed1e
5 changed files with 100 additions and 27 deletions

View file

@ -4,6 +4,7 @@ ChangeLog
unreleased unreleased
------------------- -------------------
### ✨Improvements ### ✨Improvements
* 投稿詳細ページで前後の投稿を見れるように
* 自分のfollowersートはRenoteできるように * 自分のfollowersートはRenoteできるように
* フォロー申請ページの調整 * フォロー申請ページの調整
* 壁紙設定の強化 * 壁紙設定の強化

View file

@ -7,16 +7,23 @@
<mk-error v-if="error" @retry="init()"/> <mk-error v-if="error" @retry="init()"/>
<x-list ref="notes" class="notes" :items="notes" v-slot="{ item: note }"> <div class="more" v-if="more && reversed" style="margin-bottom: var(--margin);">
<x-note :note="note" :detail="detail" :key="note.id"/>
</x-list>
<footer class="more" v-if="more">
<mk-button class="button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" @click="fetchMore()" primary> <mk-button class="button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" @click="fetchMore()" primary>
<template v-if="!moreFetching">{{ $t('loadMore') }}</template> <template v-if="!moreFetching">{{ $t('loadMore') }}</template>
<template v-if="moreFetching"><mk-loading inline/></template> <template v-if="moreFetching"><mk-loading inline/></template>
</mk-button> </mk-button>
</footer> </div>
<x-list ref="notes" class="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed">
<x-note :note="note" :detail="detail" :key="note.id"/>
</x-list>
<div class="more" v-if="more && !reversed" style="margin-top: var(--margin);">
<mk-button class="button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" @click="fetchMore()" primary>
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
<template v-if="moreFetching"><mk-loading inline/></template>
</mk-button>
</div>
</div> </div>
</template> </template>
@ -67,6 +74,10 @@ export default Vue.extend({
notes(): any[] { notes(): any[] {
return this.extract ? this.extract(this.items) : this.items; return this.extract ? this.extract(this.items) : this.items;
}, },
reversed(): boolean {
return this.pagination.reversed;
}
}, },
methods: { methods: {
@ -92,14 +103,14 @@ export default Vue.extend({
} }
> .notes { > .notes {
> ::v-deep * { > ::v-deep *:not(:last-child) {
margin-bottom: var(--marginFull); margin-bottom: var(--marginFull);
} }
} }
&.max-width_500px { &.max-width_500px {
> .notes { > .notes {
> ::v-deep * { > ::v-deep *:not(:last-child) {
margin-bottom: var(--marginHalf); margin-bottom: var(--marginHalf);
} }
} }

View file

@ -4,9 +4,19 @@
<portal to="title" v-if="note">{{ $t('noteOf', { user: note.user.name }) }}</portal> <portal to="title" v-if="note">{{ $t('noteOf', { user: note.user.name }) }}</portal>
<transition name="zoom" mode="out-in"> <transition name="zoom" mode="out-in">
<x-note v-if="note" :note="note" :key="note.id" :detail="true"/> <div v-if="note">
<div v-else-if="error"> <mk-button v-if="hasNext && !showNext" @click="showNext = true" primary style="margin: 0 auto var(--margin) auto;"><fa :icon="faChevronUp"/></mk-button>
<mk-error @retry="fetch()"/> <x-notes v-if="showNext" ref="next" :pagination="next"/>
<hr v-if="showNext"/>
<x-note :note="note" :key="note.id" :detail="true"/>
<div v-if="error">
<mk-error @retry="fetch()"/>
</div>
<mk-button v-if="hasPrev && !showPrev" @click="showPrev = true" primary style="margin: var(--margin) auto 0 auto;"><fa :icon="faChevronDown"/></mk-button>
<hr v-if="showPrev"/>
<x-notes v-if="showPrev" ref="prev" :pagination="prev" style="margin-top: var(--margin);"/>
</div> </div>
</transition> </transition>
</div> </div>
@ -14,9 +24,12 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';
import i18n from '../i18n'; import i18n from '../i18n';
import Progress from '../scripts/loading'; import Progress from '../scripts/loading';
import XNote from '../components/note.vue'; import XNote from '../components/note.vue';
import XNotes from '../components/notes.vue';
import MkButton from '../components/ui/button.vue';
export default Vue.extend({ export default Vue.extend({
i18n, i18n,
@ -26,12 +39,36 @@ export default Vue.extend({
}; };
}, },
components: { components: {
XNote XNote,
XNotes,
MkButton,
}, },
data() { data() {
return { return {
note: null, note: null,
hasPrev: false,
hasNext: false,
showPrev: false,
showNext: false,
error: null, error: null,
prev: {
endpoint: 'users/notes',
limit: 10,
params: init => ({
userId: this.note.userId,
untilId: this.note.id,
})
},
next: {
reversed: true,
endpoint: 'users/notes',
limit: 10,
params: init => ({
userId: this.note.userId,
sinceId: this.note.id,
})
},
faChevronUp, faChevronDown
}; };
}, },
watch: { watch: {
@ -46,7 +83,22 @@ export default Vue.extend({
this.$root.api('notes/show', { this.$root.api('notes/show', {
noteId: this.$route.params.note noteId: this.$route.params.note
}).then(note => { }).then(note => {
this.note = note; Promise.all([
this.$root.api('users/notes', {
userId: note.userId,
untilId: note.id,
limit: 1,
}),
this.$root.api('users/notes', {
userId: note.userId,
sinceId: note.id,
limit: 1,
}),
]).then(([prev, next]) => {
this.hasPrev = prev.length !== 0;
this.hasNext = next.length !== 0;
this.note = note;
});
}).catch(e => { }).catch(e => {
this.error = e; this.error = e;
}).finally(() => { }).finally(() => {

View file

@ -64,18 +64,18 @@ export default (opts) => ({
if (params && params.then) params = await params; if (params && params.then) params = await params;
const endpoint = typeof this.pagination.endpoint === 'function' ? this.pagination.endpoint() : this.pagination.endpoint; const endpoint = typeof this.pagination.endpoint === 'function' ? this.pagination.endpoint() : this.pagination.endpoint;
await this.$root.api(endpoint, { await this.$root.api(endpoint, {
...params,
limit: this.pagination.noPaging ? (this.pagination.limit || 10) : (this.pagination.limit || 10) + 1, limit: this.pagination.noPaging ? (this.pagination.limit || 10) : (this.pagination.limit || 10) + 1,
...params }).then(items => {
}).then(x => { if (!this.pagination.noPaging && (items.length === (this.pagination.limit || 10) + 1)) {
if (!this.pagination.noPaging && (x.length === (this.pagination.limit || 10) + 1)) { items.pop();
x.pop(); this.items = this.pagination.reversed ? [...items].reverse() : items;
this.items = x;
this.more = true; this.more = true;
} else { } else {
this.items = x; this.items = this.pagination.reversed ? [...items].reverse() : items;
this.more = false; this.more = false;
} }
this.offset = x.length; this.offset = items.length;
this.inited = true; this.inited = true;
this.fetching = false; this.fetching = false;
if (opts.after) opts.after(this, null); if (opts.after) opts.after(this, null);
@ -93,23 +93,25 @@ export default (opts) => ({
if (params && params.then) params = await params; if (params && params.then) params = await params;
const endpoint = typeof this.pagination.endpoint === 'function' ? this.pagination.endpoint() : this.pagination.endpoint; const endpoint = typeof this.pagination.endpoint === 'function' ? this.pagination.endpoint() : this.pagination.endpoint;
await this.$root.api(endpoint, { await this.$root.api(endpoint, {
...params,
limit: SECOND_FETCH_LIMIT + 1, limit: SECOND_FETCH_LIMIT + 1,
...(this.pagination.offsetMode ? { ...(this.pagination.offsetMode ? {
offset: this.offset, offset: this.offset,
} : this.pagination.reversed ? {
sinceId: this.items[0].id,
} : { } : {
untilId: this.items[this.items.length - 1].id, untilId: this.items[this.items.length - 1].id,
}), }),
...params }).then(items => {
}).then(x => { if (items.length === SECOND_FETCH_LIMIT + 1) {
if (x.length === SECOND_FETCH_LIMIT + 1) { items.pop();
x.pop(); this.items = this.pagination.reversed ? [...items].reverse().concat(this.items) : this.items.concat(items);
this.items = this.items.concat(x);
this.more = true; this.more = true;
} else { } else {
this.items = this.items.concat(x); this.items = this.pagination.reversed ? [...items].reverse().concat(this.items) : this.items.concat(items);
this.more = false; this.more = false;
} }
this.offset += x.length; this.offset += items.length;
this.moreFetching = false; this.moreFetching = false;
}, e => { }, e => {
this.moreFetching = false; this.moreFetching = false;

View file

@ -128,6 +128,13 @@ a {
} }
} }
hr {
margin: var(--margin) 0 var(--margin) 0;
border: none;
height: 1px;
background: var(--divider);
}
#nprogress { #nprogress {
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;