From 43b9a9e618f4e1345d303f78a437454ccf685f6a Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 22 Jun 2022 23:40:53 +0900 Subject: [PATCH] enhance(client): tweak ui --- ...stance-info.vue => instance-card-mini.vue} | 8 +- .../client/src/components/user-card-mini.vue | 95 +++++++++++++++++++ packages/client/src/pages/admin/users.vue | 76 ++------------- packages/client/src/pages/federation.vue | 4 +- packages/client/src/pages/user-info.vue | 10 +- 5 files changed, 119 insertions(+), 74 deletions(-) rename packages/client/src/components/{instance-info.vue => instance-card-mini.vue} (90%) create mode 100644 packages/client/src/components/user-card-mini.vue diff --git a/packages/client/src/components/instance-info.vue b/packages/client/src/components/instance-card-mini.vue similarity index 90% rename from packages/client/src/components/instance-info.vue rename to packages/client/src/components/instance-card-mini.vue index e55c1d821..edcd576ce 100644 --- a/packages/client/src/components/instance-info.vue +++ b/packages/client/src/components/instance-card-mini.vue @@ -2,8 +2,8 @@ <div :class="[$style.root, { yellow: instance.isNotResponding, red: instance.isBlocked, gray: instance.isSuspended }]"> <img v-if="instance.iconUrl" class="icon" :src="instance.iconUrl" alt=""/> <div class="body"> - <span class="host">{{ instance.host }}</span> - <span class="sub">{{ instance.softwareName || '?' }} {{ instance.softwareVersion }}</span> + <span class="host">{{ instance.name ?? instance.host }}</span> + <span class="sub _monospace"><b>{{ instance.host }}</b> / {{ instance.softwareName || '?' }} {{ instance.softwareVersion }}</span> </div> <MkMiniChart v-if="chart" class="chart" :src="chart.requests.received"/> </div> @@ -20,7 +20,7 @@ const props = defineProps<{ const chart = $ref(null); -os.api('charts/instance', { host: props.instance.host, limit: 16, span: 'hour' }).then(res => { +os.api('charts/instance', { host: props.instance.host, limit: 16, span: 'day' }).then(res => { chart = res; }); </script> @@ -42,7 +42,7 @@ os.api('charts/instance', { host: props.instance.host, limit: 16, span: 'hour' } height: ($bodyTitleHieght + $bodyInfoHieght); object-fit: cover; border-radius: 4px; - margin-right: 8px; + margin-right: 10px; } > :global(.body) { diff --git a/packages/client/src/components/user-card-mini.vue b/packages/client/src/components/user-card-mini.vue new file mode 100644 index 000000000..9a286a1a8 --- /dev/null +++ b/packages/client/src/components/user-card-mini.vue @@ -0,0 +1,95 @@ +<template> +<div :class="[$style.root, { yellow: user.isSilenced, red: user.isSuspended, gray: false }]"> + <MkAvatar class="avatar" :user="user" :disable-link="true" :show-indicator="true"/> + <div class="body"> + <span class="name"><MkUserName class="name" :user="user"/></span> + <span class="sub"><span class="acct _monospace">@{{ acct(user) }}</span></span> + </div> + <MkMiniChart v-if="chart" class="chart" :src="chart.inc"/> +</div> +</template> + +<script lang="ts" setup> +import * as misskey from 'misskey-js'; +import MkMiniChart from '@/components/mini-chart.vue'; +import * as os from '@/os'; +import { acct } from '@/filters/user'; + +const props = defineProps<{ + user: misskey.entities.User; +}>(); + +const chart = $ref(null); + +os.api('charts/user/notes', { userId: props.user.id, limit: 16, span: 'day' }).then(res => { + chart = res; +}); +</script> + +<style lang="scss" module> +.root { + $bodyTitleHieght: 18px; + $bodyInfoHieght: 16px; + + display: flex; + align-items: center; + padding: 16px; + background: var(--panel); + border-radius: 8px; + + > :global(.avatar) { + display: block; + width: ($bodyTitleHieght + $bodyInfoHieght); + height: ($bodyTitleHieght + $bodyInfoHieght); + margin-right: 12px; + } + + > :global(.body) { + flex: 1; + overflow: hidden; + font-size: 0.9em; + color: var(--fg); + padding-right: 8px; + + > :global(.name) { + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: $bodyTitleHieght; + } + + > :global(.sub) { + font-size: 75%; + opacity: 0.7; + line-height: $bodyInfoHieght; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + + > :global(.chart) { + height: 30px; + } + + &:global(.yellow) { + --c: rgb(255 196 0 / 15%); + background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%); + background-size: 16px 16px; + } + + &:global(.red) { + --c: rgb(255 0 0 / 15%); + background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%); + background-size: 16px 16px; + } + + &:global(.gray) { + --c: var(--bg); + background-image: linear-gradient(45deg, var(--c) 16.67%, transparent 16.67%, transparent 50%, var(--c) 50%, var(--c) 66.67%, transparent 66.67%, transparent 100%); + background-size: 16px 16px; + } +} +</style> diff --git a/packages/client/src/pages/admin/users.vue b/packages/client/src/pages/admin/users.vue index dccf952ba..ce377074c 100644 --- a/packages/client/src/pages/admin/users.vue +++ b/packages/client/src/pages/admin/users.vue @@ -41,25 +41,9 @@ </div> <MkPagination v-slot="{items}" ref="paginationComponent" :pagination="pagination" class="users"> - <button v-for="user in items" :key="user.id" class="user _panel _button _gap" @click="show(user)"> - <MkAvatar class="avatar" :user="user" :disable-link="true" :show-indicator="true"/> - <div class="body"> - <header> - <MkUserName class="name" :user="user"/> - <span class="acct">@{{ acct(user) }}</span> - <span v-if="user.isAdmin" class="staff"><i class="fas fa-bookmark"></i></span> - <span v-if="user.isModerator" class="staff"><i class="far fa-bookmark"></i></span> - <span v-if="user.isSilenced" class="punished"><i class="fas fa-microphone-slash"></i></span> - <span v-if="user.isSuspended" class="punished"><i class="fas fa-snowflake"></i></span> - </header> - <div> - <span>{{ $ts.lastUsed }}: <MkTime v-if="user.updatedAt" :time="user.updatedAt" mode="detail"/></span> - </div> - <div> - <span>{{ $ts.registeredDate }}: <MkTime :time="user.createdAt" mode="detail"/></span> - </div> - </div> - </button> + <MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${new Date(user.updatedAt).toLocaleString()}`" class="user" :to="`/user-info/${user.id}`" :behavior="'window'"> + <MkUserCardMini :user="user"/> + </MkA> </MkPagination> </div> </div> @@ -74,11 +58,11 @@ import XHeader from './_header_.vue'; import MkInput from '@/components/form/input.vue'; import MkSelect from '@/components/form/select.vue'; import MkPagination from '@/components/ui/pagination.vue'; -import { acct } from '@/filters/user'; import * as os from '@/os'; import { lookupUser } from '@/scripts/lookup-user'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +import MkUserCardMini from '@/components/user-card-mini.vue'; let paginationComponent = $ref<InstanceType<typeof MkPagination>>(); @@ -174,54 +158,12 @@ definePageMetadata(computed(() => ({ > .users { margin-top: var(--margin); + display: grid; + grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); + grid-gap: 12px; - > .user { - display: flex; - width: 100%; - box-sizing: border-box; - text-align: left; - align-items: center; - padding: 16px; - - &:hover { - color: var(--accent); - } - - > .avatar { - width: 60px; - height: 60px; - } - - > .body { - margin-left: 0.3em; - padding: 0 8px; - flex: 1; - - @media (max-width: 500px) { - font-size: 14px; - } - - > header { - > .name { - font-weight: bold; - } - - > .acct { - margin-left: 8px; - opacity: 0.7; - } - - > .staff { - margin-left: 0.5em; - color: var(--badge); - } - - > .punished { - margin-left: 0.5em; - color: #4dabf7; - } - } - } + > .user:hover { + text-decoration: none; } } } diff --git a/packages/client/src/pages/federation.vue b/packages/client/src/pages/federation.vue index 38d42f2be..bbd1bd352 100644 --- a/packages/client/src/pages/federation.vue +++ b/packages/client/src/pages/federation.vue @@ -42,7 +42,7 @@ <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination"> <div class="dqokceoi"> <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Last communicated: ${new Date(instance.lastCommunicatedAt).toLocaleString()}\nStatus: ${getStatus(instance)}`" class="instance" :to="`/instance-info/${instance.host}`" :behavior="'window'"> - <MkInstanceInfo :instance="instance"/> + <MkInstanceCardMini :instance="instance"/> </MkA> </div> </MkPagination> @@ -57,7 +57,7 @@ import MkButton from '@/components/ui/button.vue'; import MkInput from '@/components/form/input.vue'; import MkSelect from '@/components/form/select.vue'; import MkPagination from '@/components/ui/pagination.vue'; -import MkInstanceInfo from '@/components/instance-info.vue'; +import MkInstanceCardMini from '@/components/instance-card-mini.vue'; import FormSplit from '@/components/form/split.vue'; import * as os from '@/os'; import { i18n } from '@/i18n'; diff --git a/packages/client/src/pages/user-info.vue b/packages/client/src/pages/user-info.vue index 67fc5ba7e..ad11ae045 100644 --- a/packages/client/src/pages/user-info.vue +++ b/packages/client/src/pages/user-info.vue @@ -77,6 +77,10 @@ </div> </div> </div> + <div v-else-if="tab === 'ap'" class="_formRoot"> + <MkObjectView v-if="ap" tall :value="user"> + </MkObjectView> + </div> <div v-else-if="tab === 'raw'" class="_formRoot"> <MkObjectView v-if="info && $i.isAdmin" tall :value="info"> </MkObjectView> @@ -225,7 +229,7 @@ watch(() => props.userId, () => { watch(() => user, () => { os.api('ap/get', { - uri: user.uri || `${url}/users/${user.id}`, + uri: user.uri ?? `${url}/users/${user.id}`, }).then(res => { ap = res; }); @@ -241,6 +245,10 @@ const headerTabs = $computed(() => [{ key: 'chart', title: i18n.ts.charts, icon: 'fas fa-chart-simple', +}, { + key: 'ap', + title: 'AP', + icon: 'fas fa-share-alt', }, { key: 'raw', title: 'Raw data',