summaryrefslogtreecommitdiff
path: root/src/client/pages/user
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-11-12 02:02:25 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-11-12 02:02:25 +0900
commit0e4a111f81cceed275d9bec2695f6e401fb654d8 (patch)
tree40874799472fa07416f17b50a398ac33b7771905 /src/client/pages/user
parentupdate deps (diff)
downloadmisskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.gz
misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.bz2
misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.zip
refactoring
Resolve #7779
Diffstat (limited to 'src/client/pages/user')
-rw-r--r--src/client/pages/user/clips.vue50
-rw-r--r--src/client/pages/user/follow-list.vue65
-rw-r--r--src/client/pages/user/gallery.vue56
-rw-r--r--src/client/pages/user/index.activity.vue34
-rw-r--r--src/client/pages/user/index.photos.vue107
-rw-r--r--src/client/pages/user/index.timeline.vue68
-rw-r--r--src/client/pages/user/index.vue829
-rw-r--r--src/client/pages/user/pages.vue49
-rw-r--r--src/client/pages/user/reactions.vue81
9 files changed, 0 insertions, 1339 deletions
diff --git a/src/client/pages/user/clips.vue b/src/client/pages/user/clips.vue
deleted file mode 100644
index 53ee554383..0000000000
--- a/src/client/pages/user/clips.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-<template>
-<div>
- <MkPagination :pagination="pagination" #default="{items}" ref="list">
- <MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _gap">
- <b>{{ item.name }}</b>
- <div v-if="item.description" class="description">{{ item.description }}</div>
- </MkA>
- </MkPagination>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import MkPagination from '@client/components/ui/pagination.vue';
-
-export default defineComponent({
- components: {
- MkPagination,
- },
-
- props: {
- user: {
- type: Object,
- required: true
- },
- },
-
- data() {
- return {
- pagination: {
- endpoint: 'users/clips',
- limit: 20,
- params: {
- userId: this.user.id,
- }
- },
- };
- },
-
- watch: {
- user() {
- this.$refs.list.reload();
- }
- },
-});
-</script>
-
-<style lang="scss" scoped>
-
-</style>
diff --git a/src/client/pages/user/follow-list.vue b/src/client/pages/user/follow-list.vue
deleted file mode 100644
index 1f5ab5993c..0000000000
--- a/src/client/pages/user/follow-list.vue
+++ /dev/null
@@ -1,65 +0,0 @@
-<template>
-<div>
- <MkPagination :pagination="pagination" #default="{items}" class="mk-following-or-followers" ref="list">
- <div class="users _isolated">
- <MkUserInfo class="user" v-for="user in items.map(x => type === 'following' ? x.followee : x.follower)" :user="user" :key="user.id"/>
- </div>
- </MkPagination>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import MkUserInfo from '@client/components/user-info.vue';
-import MkPagination from '@client/components/ui/pagination.vue';
-
-export default defineComponent({
- components: {
- MkPagination,
- MkUserInfo,
- },
-
- props: {
- user: {
- type: Object,
- required: true
- },
- type: {
- type: String,
- required: true
- },
- },
-
- data() {
- return {
- pagination: {
- endpoint: () => this.type === 'following' ? 'users/following' : 'users/followers',
- limit: 20,
- params: {
- userId: this.user.id,
- }
- },
- };
- },
-
- watch: {
- type() {
- this.$refs.list.reload();
- },
-
- user() {
- this.$refs.list.reload();
- }
- }
-});
-</script>
-
-<style lang="scss" scoped>
-.mk-following-or-followers {
- > .users {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
- grid-gap: var(--margin);
- }
-}
-</style>
diff --git a/src/client/pages/user/gallery.vue b/src/client/pages/user/gallery.vue
deleted file mode 100644
index c21b3e6428..0000000000
--- a/src/client/pages/user/gallery.vue
+++ /dev/null
@@ -1,56 +0,0 @@
-<template>
-<div>
- <MkPagination :pagination="pagination" #default="{items}">
- <div class="jrnovfpt">
- <MkGalleryPostPreview v-for="post in items" :post="post" :key="post.id" class="post"/>
- </div>
- </MkPagination>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import MkGalleryPostPreview from '@client/components/gallery-post-preview.vue';
-import MkPagination from '@client/components/ui/pagination.vue';
-
-export default defineComponent({
- components: {
- MkPagination,
- MkGalleryPostPreview,
- },
-
- props: {
- user: {
- type: Object,
- required: true
- },
- },
-
- data() {
- return {
- pagination: {
- endpoint: 'users/gallery/posts',
- limit: 6,
- params: () => ({
- userId: this.user.id
- })
- },
- };
- },
-
- watch: {
- user() {
- this.$refs.list.reload();
- }
- }
-});
-</script>
-
-<style lang="scss" scoped>
-.jrnovfpt {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
- grid-gap: 12px;
- margin: var(--margin);
-}
-</style>
diff --git a/src/client/pages/user/index.activity.vue b/src/client/pages/user/index.activity.vue
deleted file mode 100644
index be85c252e8..0000000000
--- a/src/client/pages/user/index.activity.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-<template>
-<MkContainer>
- <template #header><i class="fas fa-chart-bar" style="margin-right: 0.5em;"></i>{{ $ts.activity }}</template>
-
- <div style="padding: 8px;">
- <MkChart src="per-user-notes" :args="{ user, withoutAll: true }" span="day" :limit="limit" :stacked="true" :detailed="false" :aspect-ratio="6"/>
- </div>
-</MkContainer>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import * as os from '@client/os';
-import MkContainer from '@client/components/ui/container.vue';
-import MkChart from '@client/components/chart.vue';
-
-export default defineComponent({
- components: {
- MkContainer,
- MkChart,
- },
- props: {
- user: {
- type: Object,
- required: true
- },
- limit: {
- type: Number,
- required: false,
- default: 40
- }
- },
-});
-</script>
diff --git a/src/client/pages/user/index.photos.vue b/src/client/pages/user/index.photos.vue
deleted file mode 100644
index 5029c3feec..0000000000
--- a/src/client/pages/user/index.photos.vue
+++ /dev/null
@@ -1,107 +0,0 @@
-<template>
-<MkContainer :max-height="300" :foldable="true">
- <template #header><i class="fas fa-image" style="margin-right: 0.5em;"></i>{{ $ts.images }}</template>
- <div class="ujigsodd">
- <MkLoading v-if="fetching"/>
- <div class="stream" v-if="!fetching && images.length > 0">
- <MkA v-for="image in images"
- class="img"
- :to="notePage(image.note)"
- :key="image.id"
- >
- <ImgWithBlurhash :hash="image.blurhash" :src="thumbnail(image.file)" :alt="image.name" :title="image.name"/>
- </MkA>
- </div>
- <p class="empty" v-if="!fetching && images.length == 0">{{ $ts.nothing }}</p>
- </div>
-</MkContainer>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
-import notePage from '@client/filters/note';
-import * as os from '@client/os';
-import MkContainer from '@client/components/ui/container.vue';
-import ImgWithBlurhash from '@client/components/img-with-blurhash.vue';
-
-export default defineComponent({
- components: {
- MkContainer,
- ImgWithBlurhash,
- },
- props: {
- user: {
- type: Object,
- required: true
- },
- },
- data() {
- return {
- fetching: true,
- images: [],
- };
- },
- mounted() {
- const image = [
- 'image/jpeg',
- 'image/png',
- 'image/gif',
- 'image/apng',
- 'image/vnd.mozilla.apng',
- ];
- os.api('users/notes', {
- userId: this.user.id,
- fileType: image,
- excludeNsfw: this.$store.state.nsfw !== 'ignore',
- limit: 10,
- }).then(notes => {
- for (const note of notes) {
- for (const file of note.files) {
- this.images.push({
- note,
- file
- });
- }
- }
- this.fetching = false;
- });
- },
- methods: {
- thumbnail(image: any): string {
- return this.$store.state.disableShowingAnimatedImages
- ? getStaticImageUrl(image.thumbnailUrl)
- : image.thumbnailUrl;
- },
- notePage
- },
-});
-</script>
-
-<style lang="scss" scoped>
-.ujigsodd {
- padding: 8px;
-
- > .stream {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
- grid-gap: 6px;
-
- > .img {
- height: 128px;
- border-radius: 6px;
- overflow: clip;
- }
- }
-
- > .empty {
- margin: 0;
- padding: 16px;
- text-align: center;
-
- > i {
- margin-right: 4px;
- }
- }
-}
-</style>
diff --git a/src/client/pages/user/index.timeline.vue b/src/client/pages/user/index.timeline.vue
deleted file mode 100644
index c3444f26f6..0000000000
--- a/src/client/pages/user/index.timeline.vue
+++ /dev/null
@@ -1,68 +0,0 @@
-<template>
-<div class="yrzkoczt" v-sticky-container>
- <MkTab v-model="with_" class="tab">
- <option :value="null">{{ $ts.notes }}</option>
- <option value="replies">{{ $ts.notesAndReplies }}</option>
- <option value="files">{{ $ts.withFiles }}</option>
- </MkTab>
- <XNotes ref="timeline" :no-gap="true" :pagination="pagination" @before="$emit('before')" @after="e => $emit('after', e)"/>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import XNotes from '@client/components/notes.vue';
-import MkTab from '@client/components/tab.vue';
-import * as os from '@client/os';
-
-export default defineComponent({
- components: {
- XNotes,
- MkTab,
- },
-
- props: {
- user: {
- type: Object,
- required: true,
- },
- },
-
- watch: {
- user() {
- this.$refs.timeline.reload();
- },
-
- with_() {
- this.$refs.timeline.reload();
- },
- },
-
- data() {
- return {
- date: null,
- with_: null,
- pagination: {
- endpoint: 'users/notes',
- limit: 10,
- params: init => ({
- userId: this.user.id,
- includeReplies: this.with_ === 'replies',
- withFiles: this.with_ === 'files',
- untilDate: init ? undefined : (this.date ? this.date.getTime() : undefined),
- })
- }
- };
- },
-});
-</script>
-
-<style lang="scss" scoped>
-.yrzkoczt {
- > .tab {
- margin: calc(var(--margin) / 2) 0;
- padding: calc(var(--margin) / 2) 0;
- background: var(--bg);
- }
-}
-</style>
diff --git a/src/client/pages/user/index.vue b/src/client/pages/user/index.vue
deleted file mode 100644
index 04585f3fd0..0000000000
--- a/src/client/pages/user/index.vue
+++ /dev/null
@@ -1,829 +0,0 @@
-<template>
-<div>
-<transition name="fade" mode="out-in">
- <div class="ftskorzw wide" v-if="user && narrow === false">
- <MkRemoteCaution v-if="user.host != null" :href="user.url"/>
-
- <div class="banner-container" :style="style">
- <div class="banner" ref="banner" :style="style"></div>
- </div>
- <div class="contents">
- <div class="side _forceContainerFull_">
- <MkAvatar class="avatar" :user="user" :disable-preview="true" :show-indicator="true"/>
- <div class="name">
- <MkUserName :user="user" :nowrap="false" class="name"/>
- <MkAcct :user="user" :detail="true" class="acct"/>
- </div>
- <div class="followed" v-if="$i && $i.id != user.id && user.isFollowed"><span>{{ $ts.followsYou }}</span></div>
- <div class="status">
- <MkA :to="userPage(user)" :class="{ active: page === 'index' }">
- <b>{{ number(user.notesCount) }}</b>
- <span>{{ $ts.notes }}</span>
- </MkA>
- <MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }">
- <b>{{ number(user.followingCount) }}</b>
- <span>{{ $ts.following }}</span>
- </MkA>
- <MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }">
- <b>{{ number(user.followersCount) }}</b>
- <span>{{ $ts.followers }}</span>
- </MkA>
- </div>
- <div class="description">
- <Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i" :custom-emojis="user.emojis"/>
- <p v-else class="empty">{{ $ts.noAccountDescription }}</p>
- </div>
- <div class="fields system">
- <dl class="field" v-if="user.location">
- <dt class="name"><i class="fas fa-map-marker fa-fw"></i> {{ $ts.location }}</dt>
- <dd class="value">{{ user.location }}</dd>
- </dl>
- <dl class="field" v-if="user.birthday">
- <dt class="name"><i class="fas fa-birthday-cake fa-fw"></i> {{ $ts.birthday }}</dt>
- <dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ $t('yearsOld', { age }) }})</dd>
- </dl>
- <dl class="field">
- <dt class="name"><i class="fas fa-calendar-alt fa-fw"></i> {{ $ts.registeredDate }}</dt>
- <dd class="value">{{ new Date(user.createdAt).toLocaleString() }} (<MkTime :time="user.createdAt"/>)</dd>
- </dl>
- </div>
- <div class="fields" v-if="user.fields.length > 0">
- <dl class="field" v-for="(field, i) in user.fields" :key="i">
- <dt class="name">
- <Mfm :text="field.name" :plain="true" :custom-emojis="user.emojis" :colored="false"/>
- </dt>
- <dd class="value">
- <Mfm :text="field.value" :author="user" :i="$i" :custom-emojis="user.emojis" :colored="false"/>
- </dd>
- </dl>
- </div>
- <XActivity :user="user" :key="user.id" class="_gap"/>
- <XPhotos :user="user" :key="user.id" class="_gap"/>
- </div>
- <div class="main">
- <div class="actions">
- <button @click="menu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
- <MkFollowButton v-if="!$i || $i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
- </div>
- <template v-if="page === 'index'">
- <div v-if="user.pinnedNotes.length > 0" class="_gap">
- <XNote v-for="note in user.pinnedNotes" class="note _gap" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :pinned="true"/>
- </div>
- <div class="_gap">
- <XUserTimeline :user="user"/>
- </div>
- </template>
- <XFollowList v-else-if="page === 'following'" type="following" :user="user" class="_gap"/>
- <XFollowList v-else-if="page === 'followers'" type="followers" :user="user" class="_gap"/>
- <XClips v-else-if="page === 'clips'" :user="user" class="_gap"/>
- <XPages v-else-if="page === 'pages'" :user="user" class="_gap"/>
- </div>
- </div>
- </div>
- <MkSpacer v-else-if="user && narrow === true" :content-max="800">
- <div class="ftskorzw narrow" v-size="{ max: [500] }">
- <!-- TODO -->
- <!-- <div class="punished" v-if="user.isSuspended"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSuspended }}</div> -->
- <!-- <div class="punished" v-if="user.isSilenced"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSilenced }}</div> -->
-
- <div class="profile">
- <MkRemoteCaution v-if="user.host != null" :href="user.url" class="warn"/>
-
- <div class="_block main" :key="user.id">
- <div class="banner-container" :style="style">
- <div class="banner" ref="banner" :style="style"></div>
- <div class="fade"></div>
- <div class="title">
- <MkUserName class="name" :user="user" :nowrap="true"/>
- <div class="bottom">
- <span class="username"><MkAcct :user="user" :detail="true" /></span>
- <span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span>
- <span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span>
- <span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span>
- <span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span>
- </div>
- </div>
- <span class="followed" v-if="$i && $i.id != user.id && user.isFollowed">{{ $ts.followsYou }}</span>
- <div class="actions" v-if="$i">
- <button @click="menu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
- <MkFollowButton v-if="$i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/>
- </div>
- </div>
- <MkAvatar class="avatar" :user="user" :disable-preview="true" :show-indicator="true"/>
- <div class="title">
- <MkUserName :user="user" :nowrap="false" class="name"/>
- <div class="bottom">
- <span class="username"><MkAcct :user="user" :detail="true" /></span>
- <span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span>
- <span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span>
- <span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span>
- <span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span>
- </div>
- </div>
- <div class="description">
- <Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i" :custom-emojis="user.emojis"/>
- <p v-else class="empty">{{ $ts.noAccountDescription }}</p>
- </div>
- <div class="fields system">
- <dl class="field" v-if="user.location">
- <dt class="name"><i class="fas fa-map-marker fa-fw"></i> {{ $ts.location }}</dt>
- <dd class="value">{{ user.location }}</dd>
- </dl>
- <dl class="field" v-if="user.birthday">
- <dt class="name"><i class="fas fa-birthday-cake fa-fw"></i> {{ $ts.birthday }}</dt>
- <dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ $t('yearsOld', { age }) }})</dd>
- </dl>
- <dl class="field">
- <dt class="name"><i class="fas fa-calendar-alt fa-fw"></i> {{ $ts.registeredDate }}</dt>
- <dd class="value">{{ new Date(user.createdAt).toLocaleString() }} (<MkTime :time="user.createdAt"/>)</dd>
- </dl>
- </div>
- <div class="fields" v-if="user.fields.length > 0">
- <dl class="field" v-for="(field, i) in user.fields" :key="i">
- <dt class="name">
- <Mfm :text="field.name" :plain="true" :custom-emojis="user.emojis" :colored="false"/>
- </dt>
- <dd class="value">
- <Mfm :text="field.value" :author="user" :i="$i" :custom-emojis="user.emojis" :colored="false"/>
- </dd>
- </dl>
- </div>
- <div class="status">
- <MkA :to="userPage(user)" :class="{ active: page === 'index' }" v-click-anime>
- <b>{{ number(user.notesCount) }}</b>
- <span>{{ $ts.notes }}</span>
- </MkA>
- <MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }" v-click-anime>
- <b>{{ number(user.followingCount) }}</b>
- <span>{{ $ts.following }}</span>
- </MkA>
- <MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }" v-click-anime>
- <b>{{ number(user.followersCount) }}</b>
- <span>{{ $ts.followers }}</span>
- </MkA>
- </div>
- </div>
- </div>
-
- <div class="contents">
- <template v-if="page === 'index'">
- <div>
- <div v-if="user.pinnedNotes.length > 0" class="_gap">
- <XNote v-for="note in user.pinnedNotes" class="note _block" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :pinned="true"/>
- </div>
- <MkInfo v-else-if="$i && $i.id === user.id">{{ $ts.userPagePinTip }}</MkInfo>
- <XPhotos :user="user" :key="user.id"/>
- <XActivity :user="user" :key="user.id" style="margin-top: var(--margin);"/>
- </div>
- <div>
- <XUserTimeline :user="user"/>
- </div>
- </template>
- <XFollowList v-else-if="page === 'following'" type="following" :user="user" class="_content _gap"/>
- <XFollowList v-else-if="page === 'followers'" type="followers" :user="user" class="_content _gap"/>
- <XReactions v-else-if="page === 'reactions'" :user="user" class="_gap"/>
- <XClips v-else-if="page === 'clips'" :user="user" class="_gap"/>
- <XPages v-else-if="page === 'pages'" :user="user" class="_gap"/>
- <XGallery v-else-if="page === 'gallery'" :user="user" class="_gap"/>
- </div>
- </div>
- </MkSpacer>
- <MkError v-else-if="error" @retry="fetch()"/>
- <MkLoading v-else/>
-</transition>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent, defineAsyncComponent, computed } from 'vue';
-import * as age from 's-age';
-import XUserTimeline from './index.timeline.vue';
-import XNote from '@client/components/note.vue';
-import MkFollowButton from '@client/components/follow-button.vue';
-import MkContainer from '@client/components/ui/container.vue';
-import MkFolder from '@client/components/ui/folder.vue';
-import MkRemoteCaution from '@client/components/remote-caution.vue';
-import MkTab from '@client/components/tab.vue';
-import MkInfo from '@client/components/ui/info.vue';
-import Progress from '@client/scripts/loading';
-import { parseAcct } from '@/misc/acct';
-import { getScrollPosition } from '@client/scripts/scroll';
-import { getUserMenu } from '@client/scripts/get-user-menu';
-import number from '@client/filters/number';
-import { userPage, acct as getAcct } from '@client/filters/user';
-import * as os from '@client/os';
-import * as symbols from '@client/symbols';
-
-export default defineComponent({
- components: {
- XUserTimeline,
- XNote,
- MkFollowButton,
- MkContainer,
- MkRemoteCaution,
- MkFolder,
- MkTab,
- MkInfo,
- XFollowList: defineAsyncComponent(() => import('./follow-list.vue')),
- XReactions: defineAsyncComponent(() => import('./reactions.vue')),
- XClips: defineAsyncComponent(() => import('./clips.vue')),
- XPages: defineAsyncComponent(() => import('./pages.vue')),
- XGallery: defineAsyncComponent(() => import('./gallery.vue')),
- XPhotos: defineAsyncComponent(() => import('./index.photos.vue')),
- XActivity: defineAsyncComponent(() => import('./index.activity.vue')),
- },
-
- props: {
- acct: {
- type: String,
- required: true
- },
- page: {
- type: String,
- required: false,
- default: 'index'
- }
- },
-
- data() {
- return {
- [symbols.PAGE_INFO]: computed(() => this.user ? {
- icon: 'fas fa-user',
- title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`,
- subtitle: `@${getAcct(this.user)}`,
- userName: this.user,
- avatar: this.user,
- path: `/@${this.user.username}`,
- share: {
- title: this.user.name,
- },
- bg: 'var(--bg)',
- tabs: [{
- active: this.page === 'index',
- title: this.$ts.overview,
- icon: 'fas fa-home',
- onClick: () => { this.$router.push('/@' + getAcct(this.user)); },
- }, ...(this.$i && (this.$i.id === this.user.id)) || this.user.publicReactions ? [{
- active: this.page === 'reactions',
- title: this.$ts.reaction,
- icon: 'fas fa-laugh',
- onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/reactions'); },
- }] : [], {
- active: this.page === 'clips',
- title: this.$ts.clips,
- icon: 'fas fa-paperclip',
- onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/clips'); },
- }, {
- active: this.page === 'pages',
- title: this.$ts.pages,
- icon: 'fas fa-file-alt',
- onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/pages'); },
- }, {
- active: this.page === 'gallery',
- title: this.$ts.gallery,
- icon: 'fas fa-icons',
- onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/gallery'); },
- }],
- } : null),
- user: null,
- error: null,
- parallaxAnimationId: null,
- narrow: null,
- };
- },
-
- computed: {
- style(): any {
- if (this.user.bannerUrl == null) return {};
- return {
- backgroundImage: `url(${ this.user.bannerUrl })`
- };
- },
-
- age(): number {
- return age(this.user.birthday);
- }
- },
-
- watch: {
- acct: 'fetch'
- },
-
- created() {
- this.fetch();
- },
-
- mounted() {
- window.requestAnimationFrame(this.parallaxLoop);
- this.narrow = true//this.$el.clientWidth < 1000;
- },
-
- beforeUnmount() {
- window.cancelAnimationFrame(this.parallaxAnimationId);
- },
-
- methods: {
- getAcct,
-
- fetch() {
- if (this.acct == null) return;
- this.user = null;
- Progress.start();
- os.api('users/show', parseAcct(this.acct)).then(user => {
- this.user = user;
- }).catch(e => {
- this.error = e;
- }).finally(() => {
- Progress.done();
- });
- },
-
- menu(ev) {
- os.popupMenu(getUserMenu(this.user), ev.currentTarget || ev.target);
- },
-
- parallaxLoop() {
- this.parallaxAnimationId = window.requestAnimationFrame(this.parallaxLoop);
- this.parallax();
- },
-
- parallax() {
- const banner = this.$refs.banner as any;
- if (banner == null) return;
-
- const top = getScrollPosition(this.$el);
-
- if (top < 0) return;
-
- const z = 1.75; // 奥行き(小さいほど奥)
- const pos = -(top / z);
- banner.style.backgroundPosition = `center calc(50% - ${pos}px)`;
- },
-
- pinnedNoteUpdated(oldValue, newValue) {
- const i = this.user.pinnedNotes.findIndex(n => n === oldValue);
- this.user.pinnedNotes[i] = newValue;
- },
-
- number,
-
- userPage
- }
-});
-</script>
-
-<style lang="scss" scoped>
-.fade-enter-active,
-.fade-leave-active {
- transition: opacity 0.125s ease;
-}
-.fade-enter-from,
-.fade-leave-to {
- opacity: 0;
-}
-
-.ftskorzw.wide {
-
- > .banner-container {
- position: relative;
- height: 300px;
- overflow: hidden;
- background-size: cover;
- background-position: center;
-
- > .banner {
- height: 100%;
- background-color: #4c5e6d;
- background-size: cover;
- background-position: center;
- box-shadow: 0 0 128px rgba(0, 0, 0, 0.5) inset;
- will-change: background-position;
- }
- }
-
- > .contents {
- display: flex;
- padding: 16px;
-
- > .side {
- width: 360px;
-
- > .avatar {
- display: block;
- width: 180px;
- height: 180px;
- margin: -130px auto 0 auto;
- }
-
- > .name {
- padding: 16px 0px 20px 0;
- text-align: center;
-
- > .name {
- display: block;
- font-size: 1.75em;
- font-weight: bold;
- }
- }
-
- > .followed {
- text-align: center;
-
- > span {
- display: inline-block;
- font-size: 80%;
- padding: 8px 12px;
- margin-bottom: 20px;
- border: solid 0.5px var(--divider);
- border-radius: 999px;
- }
- }
-
- > .status {
- display: flex;
- padding: 20px 16px;
- border-top: solid 0.5px var(--divider);
- font-size: 90%;
-
- > a {
- flex: 1;
- text-align: center;
-
- &.active {
- color: var(--accent);
- }
-
- &:hover {
- text-decoration: none;
- }
-
- > b {
- display: block;
- line-height: 16px;
- }
-
- > span {
- font-size: 75%;
- }
- }
- }
-
- > .description {
- padding: 20px 16px;
- border-top: solid 0.5px var(--divider);
- font-size: 90%;
- }
-
- > .fields {
- padding: 20px 16px;
- border-top: solid 0.5px var(--divider);
- font-size: 90%;
-
- > .field {
- display: flex;
- padding: 0;
- margin: 0;
- align-items: center;
-
- &:not(:last-child) {
- margin-bottom: 8px;
- }
-
- > .name {
- width: 30%;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- font-weight: bold;
- }
-
- > .value {
- width: 70%;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- margin: 0;
- }
- }
- }
- }
-
- > .main {
- flex: 1;
- margin-left: var(--margin);
- min-width: 0;
-
- > .nav {
- display: flex;
- align-items: center;
- margin-top: var(--margin);
- //font-size: 120%;
- font-weight: bold;
-
- > .link {
- display: inline-block;
- padding: 15px 24px 12px 24px;
- text-align: center;
- border-bottom: solid 3px transparent;
-
- &:hover {
- text-decoration: none;
- }
-
- &.active {
- color: var(--accent);
- border-bottom-color: var(--accent);
- }
-
- &:not(.active):hover {
- color: var(--fgHighlighted);
- }
-
- > .icon {
- margin-right: 6px;
- }
- }
-
- > .actions {
- display: flex;
- align-items: center;
- margin-left: auto;
-
- > .menu {
- padding: 12px 16px;
- }
- }
- }
- }
- }
-}
-
-.ftskorzw.narrow {
- box-sizing: border-box;
- overflow: clip;
- background: var(--bg);
-
- > .punished {
- font-size: 0.8em;
- padding: 16px;
- }
-
- > .profile {
-
- > .main {
- position: relative;
- overflow: hidden;
-
- > .banner-container {
- position: relative;
- height: 250px;
- overflow: hidden;
- background-size: cover;
- background-position: center;
-
- > .banner {
- height: 100%;
- background-color: #4c5e6d;
- background-size: cover;
- background-position: center;
- box-shadow: 0 0 128px rgba(0, 0, 0, 0.5) inset;
- will-change: background-position;
- }
-
- > .fade {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 78px;
- background: linear-gradient(transparent, rgba(#000, 0.7));
- }
-
- > .followed {
- position: absolute;
- top: 12px;
- left: 12px;
- padding: 4px 8px;
- color: #fff;
- background: rgba(0, 0, 0, 0.7);
- font-size: 0.7em;
- border-radius: 6px;
- }
-
- > .actions {
- position: absolute;
- top: 12px;
- right: 12px;
- -webkit-backdrop-filter: var(--blur, blur(8px));
- backdrop-filter: var(--blur, blur(8px));
- background: rgba(0, 0, 0, 0.2);
- padding: 8px;
- border-radius: 24px;
-
- > .menu {
- vertical-align: bottom;
- height: 31px;
- width: 31px;
- color: #fff;
- text-shadow: 0 0 8px #000;
- font-size: 16px;
- }
-
- > .koudoku {
- margin-left: 4px;
- vertical-align: bottom;
- }
- }
-
- > .title {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- padding: 0 0 8px 154px;
- box-sizing: border-box;
- color: #fff;
-
- > .name {
- display: block;
- margin: 0;
- line-height: 32px;
- font-weight: bold;
- font-size: 1.8em;
- text-shadow: 0 0 8px #000;
- }
-
- > .bottom {
- > * {
- display: inline-block;
- margin-right: 16px;
- line-height: 20px;
- opacity: 0.8;
-
- &.username {
- font-weight: bold;
- }
- }
- }
- }
- }
-
- > .title {
- display: none;
- text-align: center;
- padding: 50px 8px 16px 8px;
- font-weight: bold;
- border-bottom: solid 0.5px var(--divider);
-
- > .bottom {
- > * {
- display: inline-block;
- margin-right: 8px;
- opacity: 0.8;
- }
- }
- }
-
- > .avatar {
- display: block;
- position: absolute;
- top: 170px;
- left: 16px;
- z-index: 2;
- width: 120px;
- height: 120px;
- box-shadow: 1px 1px 3px rgba(#000, 0.2);
- }
-
- > .description {
- padding: 24px 24px 24px 154px;
- font-size: 0.95em;
-
- > .empty {
- margin: 0;
- opacity: 0.5;
- }
- }
-
- > .fields {
- padding: 24px;
- font-size: 0.9em;
- border-top: solid 0.5px var(--divider);
-
- > .field {
- display: flex;
- padding: 0;
- margin: 0;
- align-items: center;
-
- &:not(:last-child) {
- margin-bottom: 8px;
- }
-
- > .name {
- width: 30%;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- font-weight: bold;
- text-align: center;
- }
-
- > .value {
- width: 70%;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- margin: 0;
- }
- }
-
- &.system > .field > .name {
- }
- }
-
- > .status {
- display: flex;
- padding: 24px;
- border-top: solid 0.5px var(--divider);
-
- > a {
- flex: 1;
- text-align: center;
-
- &.active {
- color: var(--accent);
- }
-
- &:hover {
- text-decoration: none;
- }
-
- > b {
- display: block;
- line-height: 16px;
- }
-
- > span {
- font-size: 70%;
- }
- }
- }
- }
- }
-
- > .contents {
- > .content {
- margin-bottom: var(--margin);
- }
- }
-
- &.max-width_500px {
- > .profile > .main {
- > .banner-container {
- height: 140px;
-
- > .fade {
- display: none;
- }
-
- > .title {
- display: none;
- }
- }
-
- > .title {
- display: block;
- }
-
- > .avatar {
- top: 90px;
- left: 0;
- right: 0;
- width: 92px;
- height: 92px;
- margin: auto;
- }
-
- > .description {
- padding: 16px;
- text-align: center;
- }
-
- > .fields {
- padding: 16px;
- }
-
- > .status {
- padding: 16px;
- }
- }
-
- > .contents {
- > .nav {
- font-size: 80%;
- }
- }
- }
-}
-</style>
diff --git a/src/client/pages/user/pages.vue b/src/client/pages/user/pages.vue
deleted file mode 100644
index ece418cf62..0000000000
--- a/src/client/pages/user/pages.vue
+++ /dev/null
@@ -1,49 +0,0 @@
-<template>
-<div>
- <MkPagination :pagination="pagination" #default="{items}" ref="list">
- <MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/>
- </MkPagination>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import MkPagePreview from '@client/components/page-preview.vue';
-import MkPagination from '@client/components/ui/pagination.vue';
-
-export default defineComponent({
- components: {
- MkPagination,
- MkPagePreview,
- },
-
- props: {
- user: {
- type: Object,
- required: true
- },
- },
-
- data() {
- return {
- pagination: {
- endpoint: 'users/pages',
- limit: 20,
- params: {
- userId: this.user.id,
- }
- },
- };
- },
-
- watch: {
- user() {
- this.$refs.list.reload();
- }
- }
-});
-</script>
-
-<style lang="scss" scoped>
-
-</style>
diff --git a/src/client/pages/user/reactions.vue b/src/client/pages/user/reactions.vue
deleted file mode 100644
index 5ac7e01027..0000000000
--- a/src/client/pages/user/reactions.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-<template>
-<div>
- <MkPagination :pagination="pagination" #default="{items}" ref="list">
- <div v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _gap afdcfbfb">
- <div class="header">
- <MkAvatar class="avatar" :user="user"/>
- <MkReactionIcon class="reaction" :reaction="item.type" :custom-emojis="item.note.emojis" :no-style="true"/>
- <MkTime :time="item.createdAt" class="createdAt"/>
- </div>
- <MkNote :note="item.note" @update:note="updated(note, $event)" :key="item.id"/>
- </div>
- </MkPagination>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import MkPagination from '@client/components/ui/pagination.vue';
-import MkNote from '@client/components/note.vue';
-import MkReactionIcon from '@client/components/reaction-icon.vue';
-
-export default defineComponent({
- components: {
- MkPagination,
- MkNote,
- MkReactionIcon,
- },
-
- props: {
- user: {
- type: Object,
- required: true
- },
- },
-
- data() {
- return {
- pagination: {
- endpoint: 'users/reactions',
- limit: 20,
- params: {
- userId: this.user.id,
- }
- },
- };
- },
-
- watch: {
- user() {
- this.$refs.list.reload();
- }
- },
-});
-</script>
-
-<style lang="scss" scoped>
-.afdcfbfb {
- > .header {
- display: flex;
- align-items: center;
- padding: 8px 16px;
- margin-bottom: 8px;
- border-bottom: solid 2px var(--divider);
-
- > .avatar {
- width: 24px;
- height: 24px;
- margin-right: 8px;
- }
-
- > .reaction {
- width: 32px;
- height: 32px;
- }
-
- > .createdAt {
- margin-left: auto;
- }
- }
-}
-</style>