diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-10-25 02:34:58 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-10-25 02:34:58 +0900 |
| commit | 6d557269c13f023d80aeeb28ddceb7337aca134c (patch) | |
| tree | f69595ca45dd0d05dc3af4404dd8205dc828ddc1 /src/client | |
| parent | Merge branch 'develop' (diff) | |
| parent | 12.94.0 (diff) | |
| download | misskey-6d557269c13f023d80aeeb28ddceb7337aca134c.tar.gz misskey-6d557269c13f023d80aeeb28ddceb7337aca134c.tar.bz2 misskey-6d557269c13f023d80aeeb28ddceb7337aca134c.zip | |
Merge branch 'develop'
Diffstat (limited to 'src/client')
59 files changed, 932 insertions, 1183 deletions
diff --git a/src/client/components/chart.vue b/src/client/components/chart.vue index 2b94bd679d..ae9a5e79b1 100644 --- a/src/client/components/chart.vue +++ b/src/client/components/chart.vue @@ -89,6 +89,16 @@ export default defineComponent({ required: false, default: false }, + stacked: { + type: Boolean, + required: false, + default: false + }, + aspectRatio: { + type: Number, + required: false, + default: null + }, }, setup(props) { @@ -157,7 +167,7 @@ export default defineComponent({ })), }, options: { - aspectRatio: 2.5, + aspectRatio: props.aspectRatio || 2.5, layout: { padding: { left: 16, @@ -174,7 +184,6 @@ export default defineComponent({ unit: props.span === 'day' ? 'month' : 'day', }, grid: { - display: props.detailed, color: gridColor, borderColor: 'rgb(0, 0, 0, 0)', }, @@ -190,6 +199,7 @@ export default defineComponent({ }, y: { position: 'left', + stacked: props.stacked, grid: { color: gridColor, borderColor: 'rgb(0, 0, 0, 0)', @@ -204,6 +214,7 @@ export default defineComponent({ }, plugins: { legend: { + display: props.detailed, position: 'bottom', labels: { boxWidth: 16, @@ -583,6 +594,30 @@ export default defineComponent({ }; }; + const fetchPerUserNotesChart = async (): Promise<typeof data> => { + const raw = await os.api('charts/user/notes', { userId: props.args.user.id, limit: props.limit, span: props.span }); + return { + series: [...(props.args.withoutAll ? [] : [{ + name: 'All', + type: 'line', + borderDash: [5, 5], + data: format(sum(raw.inc, negate(raw.dec))), + }]), { + name: 'Renotes', + type: 'area', + data: format(raw.diffs.renote), + }, { + name: 'Replies', + type: 'area', + data: format(raw.diffs.reply), + }, { + name: 'Normal', + type: 'area', + data: format(raw.diffs.normal), + }], + }; + }; + const fetchAndRender = async () => { const fetchData = () => { switch (props.src) { @@ -611,6 +646,8 @@ export default defineComponent({ case 'instance-drive-usage-total': return fetchInstanceDriveUsageChart(true); case 'instance-drive-files': return fetchInstanceDriveFilesChart(false); case 'instance-drive-files-total': return fetchInstanceDriveFilesChart(true); + + case 'per-user-notes': return fetchPerUserNotesChart(); } }; fetching.value = true; diff --git a/src/client/components/global/header.vue b/src/client/components/global/header.vue index 2bf490c98a..526db07fd3 100644 --- a/src/client/components/global/header.vue +++ b/src/client/components/global/header.vue @@ -2,8 +2,8 @@ <div class="fdidabkb" :class="{ slim: narrow, thin: thin_ }" :style="{ background: bg }" @click="onClick" ref="el"> <template v-if="info"> <div class="titleContainer" @click="showTabsPopup" v-if="!hideTitle"> - <i v-if="info.icon" class="icon" :class="info.icon"></i> - <MkAvatar v-else-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/> + <MkAvatar v-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/> + <i v-else-if="info.icon" class="icon" :class="info.icon"></i> <div class="title"> <MkUserName v-if="info.userName" :user="info.userName" :nowrap="false" class="title"/> @@ -162,11 +162,6 @@ export default defineComponent({ onUnmounted(() => { ro.disconnect(); }); - setTimeout(() => { - const currentStickyTop = getComputedStyle(el.value.parentElement).getPropertyValue('--stickyTop') || '0px'; - el.value.style.setProperty('--stickyTop', currentStickyTop); - el.value.parentElement.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${el.value.offsetHeight}px)`); - }, 100); // レンダリング順序の関係で親のstickyTopの設定が少し遅れることがあるため } }); diff --git a/src/client/components/global/sticky-container.vue b/src/client/components/global/sticky-container.vue new file mode 100644 index 0000000000..859b2c1d73 --- /dev/null +++ b/src/client/components/global/sticky-container.vue @@ -0,0 +1,74 @@ +<template> +<div ref="rootEl"> + <slot name="header"></slot> + <div ref="bodyEl"> + <slot></slot> + </div> +</div> +</template> + +<script lang="ts"> +import { defineComponent, onMounted, onUnmounted, ref } from 'vue'; + +export default defineComponent({ + props: { + autoSticky: { + type: Boolean, + required: false, + default: false, + }, + }, + + setup(props, context) { + const rootEl = ref<HTMLElement>(null); + const bodyEl = ref<HTMLElement>(null); + + const calc = () => { + const currentStickyTop = getComputedStyle(rootEl.value).getPropertyValue('--stickyTop') || '0px'; + + const header = rootEl.value.children[0]; + if (header === bodyEl.value) { + bodyEl.value.style.setProperty('--stickyTop', currentStickyTop); + } else { + bodyEl.value.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${header.offsetHeight}px)`); + + if (props.autoSticky) { + header.style.setProperty('--stickyTop', currentStickyTop); + header.style.position = 'sticky'; + header.style.top = 'var(--stickyTop)'; + header.style.zIndex = '1'; + } + } + }; + + onMounted(() => { + calc(); + + const observer = new MutationObserver(() => { + setTimeout(() => { + calc(); + }, 100); + }); + + observer.observe(rootEl.value, { + attributes: false, + childList: true, + subtree: false, + }); + + onUnmounted(() => { + observer.disconnect(); + }); + }); + + return { + rootEl, + bodyEl, + }; + }, +}); +</script> + +<style lang="scss" module> + +</style> diff --git a/src/client/components/index.ts b/src/client/components/index.ts index ecf66ea0e8..2340b228f8 100644 --- a/src/client/components/index.ts +++ b/src/client/components/index.ts @@ -15,6 +15,7 @@ import error from './global/error.vue'; import ad from './global/ad.vue'; import header from './global/header.vue'; import spacer from './global/spacer.vue'; +import stickyContainer from './global/sticky-container.vue'; export default function(app: App) { app.component('I18n', i18n); @@ -32,4 +33,5 @@ export default function(app: App) { app.component('MkAd', ad); app.component('MkHeader', header); app.component('MkSpacer', spacer); + app.component('MkStickyContainer', stickyContainer); } diff --git a/src/client/components/media-image.vue b/src/client/components/media-image.vue index 863eb10272..fd5e0b5f9b 100644 --- a/src/client/components/media-image.vue +++ b/src/client/components/media-image.vue @@ -12,7 +12,6 @@ <a :href="image.url" :title="image.name" - @click.prevent="onClick" > <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> @@ -73,17 +72,6 @@ export default defineComponent({ immediate: true, }); }, - methods: { - onClick() { - if (this.$store.state.imageNewTab) { - window.open(this.image.url, '_blank'); - } else { - os.popup(ImageViewer, { - image: this.image - }, {}, 'closed'); - } - } - } }); </script> diff --git a/src/client/components/media-list.vue b/src/client/components/media-list.vue index 71767a0f9f..c499525d84 100644 --- a/src/client/components/media-list.vue +++ b/src/client/components/media-list.vue @@ -1,11 +1,11 @@ <template> -<div class="mk-media-list"> +<div class="hoawjimk"> <XBanner v-for="media in mediaList.filter(media => !previewable(media))" :media="media" :key="media.id"/> - <div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container" ref="gridOuter"> - <div :data-count="mediaList.filter(media => previewable(media)).length" :style="gridInnerStyle"> + <div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container"> + <div :data-count="mediaList.filter(media => previewable(media)).length" ref="gallery"> <template v-for="media in mediaList"> <XVideo :video="media" :key="media.id" v-if="media.type.startsWith('video')"/> - <XImage :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/> + <XImage class="image" :data-id="media.id" :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/> </template> </div> </div> @@ -13,11 +13,16 @@ </template> <script lang="ts"> -import { defineComponent } from 'vue'; +import { defineComponent, onMounted, PropType, ref } from 'vue'; +import * as misskey from 'misskey-js'; +import PhotoSwipeLightbox from 'photoswipe/dist/photoswipe-lightbox.esm.js'; +import PhotoSwipe from 'photoswipe/dist/photoswipe.esm.js'; +import 'photoswipe/dist/photoswipe.css'; import XBanner from './media-banner.vue'; import XImage from './media-image.vue'; import XVideo from './media-video.vue'; import * as os from '@client/os'; +import { defaultStore } from '@client/store'; export default defineComponent({ components: { @@ -27,63 +32,63 @@ export default defineComponent({ }, props: { mediaList: { - required: true + type: Array as PropType<misskey.entities.DriveFile[]>, + required: true, }, raw: { default: false }, }, - data() { - return { - gridInnerStyle: {}, - sizeWaiting: false - } - }, - mounted() { - this.size(); - window.addEventListener('resize', this.size); - }, - beforeUnmount() { - window.removeEventListener('resize', this.size); - }, - activated() { - this.size(); - }, - methods: { - previewable(file) { - return file.type.startsWith('video') || file.type.startsWith('image'); - }, - size() { - // for Safari bug - if (this.sizeWaiting) return; + setup(props) { + const gallery = ref(null); - this.sizeWaiting = true; + onMounted(() => { + const lightbox = new PhotoSwipeLightbox({ + dataSource: props.mediaList.filter(media => media.type.startsWith('image')).map(media => ({ + src: media.url, + w: media.properties.width, + h: media.properties.height, + alt: media.name, + })), + gallery: gallery.value, + children: '.image', + thumbSelector: '.image', + pswpModule: PhotoSwipe + }); - window.requestAnimationFrame(() => { - this.sizeWaiting = false; + lightbox.on('itemData', (e) => { + const { itemData } = e; - if (this.$refs.gridOuter) { - let height = 287; - const parent = this.$parent.$el; + // element is children + const { element } = itemData; - if (this.$refs.gridOuter.clientHeight) { - height = this.$refs.gridOuter.clientHeight; - } else if (parent) { - height = parent.getBoundingClientRect().width * 9 / 16; - } + const id = element.dataset.id; + const file = props.mediaList.find(media => media.id === id); - this.gridInnerStyle = { height: `${height}px` }; - } else { - this.gridInnerStyle = {}; - } + itemData.src = file.url; + itemData.w = Number(file.properties.width); + itemData.h = Number(file.properties.height); + itemData.msrc = file.thumbnailUrl; + itemData.thumbCropped = true; }); - } + + lightbox.init(); + }); + + const previewable = (file: misskey.entities.DriveFile): boolean => { + return file.type.startsWith('video') || file.type.startsWith('image'); + }; + + return { + previewable, + gallery, + }; }, }); </script> <style lang="scss" scoped> -.mk-media-list { +.hoawjimk { > .gird-container { position: relative; width: 100%; diff --git a/src/client/components/mention.vue b/src/client/components/mention.vue index b9bd6b320b..101a9020ee 100644 --- a/src/client/components/mention.vue +++ b/src/client/components/mention.vue @@ -1,6 +1,7 @@ <template> <MkA class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')"> <span class="me" v-if="isMe">{{ $ts.you }}</span> + <img class="icon" :src="`/avatar/@${username}@${host}`" alt=""> <span class="main"> <span class="username">@{{ username }}</span> <span class="host" v-if="(host != localHost) || $store.state.showFullAcct">@{{ toUnicode(host) }}</span> @@ -76,6 +77,13 @@ export default defineComponent({ vertical-align: top; } + > .icon { + width: 1.5em; + margin: 0 0.2em; + vertical-align: bottom; + border-radius: 100%; + } + > .main { > .host { opacity: 0.5; diff --git a/src/client/components/modal-page-window.vue b/src/client/components/modal-page-window.vue index cb81a974f5..e47d3dc62c 100644 --- a/src/client/components/modal-page-window.vue +++ b/src/client/components/modal-page-window.vue @@ -10,10 +10,13 @@ </span> <button class="_button" @click="$refs.modal.close()"><i class="fas fa-times"></i></button> </div> - <div class="body _fitSide_"> - <keep-alive> - <component :is="component" v-bind="props" :ref="changePage"/> - </keep-alive> + <div class="body"> + <MkStickyContainer> + <template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template> + <keep-alive> + <component :is="component" v-bind="props" :ref="changePage"/> + </keep-alive> + </MkStickyContainer> </div> </div> </MkModal> diff --git a/src/client/components/page-window.vue b/src/client/components/page-window.vue index 7d15c75d62..bc7c5b7a19 100644 --- a/src/client/components/page-window.vue +++ b/src/client/components/page-window.vue @@ -16,8 +16,11 @@ <template #headerLeft> <button v-if="history.length > 0" class="_button" @click="back()" v-tooltip="$ts.goBack"><i class="fas fa-arrow-left"></i></button> </template> - <div class="yrolvcoq _fitSide_"> - <component :is="component" v-bind="props" :ref="changePage"/> + <div class="yrolvcoq"> + <MkStickyContainer> + <template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template> + <component :is="component" v-bind="props" :ref="changePage"/> + </MkStickyContainer> </div> </XWindow> </template> diff --git a/src/client/components/queue-chart.vue b/src/client/components/queue-chart.vue index 59c9723f89..f9c3eccfb5 100644 --- a/src/client/components/queue-chart.vue +++ b/src/client/components/queue-chart.vue @@ -79,6 +79,7 @@ export default defineComponent({ pointRadius: 0, tension: 0, borderWidth: 2, + borderJoinStyle: 'round', borderColor: '#00E396', backgroundColor: alpha('#00E396', 0.1), data: [] @@ -87,6 +88,7 @@ export default defineComponent({ pointRadius: 0, tension: 0, borderWidth: 2, + borderJoinStyle: 'round', borderColor: '#00BCD4', backgroundColor: alpha('#00BCD4', 0.1), data: [] @@ -95,17 +97,21 @@ export default defineComponent({ pointRadius: 0, tension: 0, borderWidth: 2, + borderJoinStyle: 'round', borderColor: '#FFB300', backgroundColor: alpha('#FFB300', 0.1), + yAxisID: 'y2', data: [] }, { label: 'Delayed', pointRadius: 0, tension: 0, borderWidth: 2, + borderJoinStyle: 'round', borderColor: '#E53935', borderDash: [5, 5], fill: false, + yAxisID: 'y2', data: [] }], }, @@ -122,15 +128,29 @@ export default defineComponent({ scales: { x: { grid: { - display: false, + display: true, color: gridColor, borderColor: 'rgb(0, 0, 0, 0)', }, ticks: { display: false, + maxTicksLimit: 10 }, }, y: { + min: 0, + stack: 'queue', + stackWeight: 2, + grid: { + color: gridColor, + borderColor: 'rgb(0, 0, 0, 0)', + }, + }, + y2: { + min: 0, + offset: true, + stack: 'queue', + stackWeight: 1, grid: { color: gridColor, borderColor: 'rgb(0, 0, 0, 0)', diff --git a/src/client/components/reactions-viewer.details.vue b/src/client/components/reactions-viewer.details.vue index 6e7da58e20..7c49bd1d9c 100644 --- a/src/client/components/reactions-viewer.details.vue +++ b/src/client/components/reactions-viewer.details.vue @@ -1,23 +1,25 @@ <template> -<MkTooltip :source="source" ref="tooltip" @closed="$emit('closed')"> +<MkTooltip :source="source" ref="tooltip" @closed="$emit('closed')" :max-width="340"> <div class="bqxuuuey"> - <div class="info"> - <div>{{ reaction.replace('@.', '') }}</div> + <div class="reaction"> <XReactionIcon :reaction="reaction" :custom-emojis="emojis" class="icon" :no-style="true"/> + <div class="name">{{ reaction.replace('@.', '') }}</div> + </div> + <div class="users"> + <template v-if="users.length <= 10"> + <b v-for="u in users" :key="u.id" style="margin-right: 12px;"> + <MkAvatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/> + <MkUserName :user="u" :nowrap="false" style="line-height: 24px;"/> + </b> + </template> + <template v-if="10 < users.length"> + <b v-for="u in users" :key="u.id" style="margin-right: 12px;"> + <MkAvatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/> + <MkUserName :user="u" :nowrap="false" style="line-height: 24px;"/> + </b> + <span slot="omitted">+{{ count - 10 }}</span> + </template> </div> - <template v-if="users.length <= 10"> - <b v-for="u in users" :key="u.id" style="margin-right: 12px;"> - <MkAvatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/> - <MkUserName :user="u" :nowrap="false" style="line-height: 24px;"/> - </b> - </template> - <template v-if="10 < users.length"> - <b v-for="u in users" :key="u.id" style="margin-right: 12px;"> - <MkAvatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/> - <MkUserName :user="u" :nowrap="false" style="line-height: 24px;"/> - </b> - <span slot="omitted">+{{ count - 10 }}</span> - </template> </div> </MkTooltip> </template> @@ -59,8 +61,11 @@ export default defineComponent({ <style lang="scss" scoped> .bqxuuuey { - > .info { - padding: 0 0 8px 0; + display: flex; + + > .reaction { + flex: 1; + max-width: 100px; text-align: center; > .icon { @@ -68,6 +73,19 @@ export default defineComponent({ width: 60px; margin: 0 auto; } + + > .name { + font-size: 0.9em; + } + } + + > .users { + flex: 1; + min-width: 0; + font-size: 0.9em; + border-left: solid 0.5px var(--divider); + padding-left: 10px; + margin-left: 10px; } } </style> diff --git a/src/client/components/reactions-viewer.reaction.vue b/src/client/components/reactions-viewer.reaction.vue index 6754d13815..f47ba83f61 100644 --- a/src/client/components/reactions-viewer.reaction.vue +++ b/src/client/components/reactions-viewer.reaction.vue @@ -177,6 +177,7 @@ export default defineComponent({ > span { font-size: 0.9em; line-height: 32px; + margin: 0 0 0 4px; } } </style> diff --git a/src/client/components/ui/folder.vue b/src/client/components/ui/folder.vue index d0616a57c1..3997421d08 100644 --- a/src/client/components/ui/folder.vue +++ b/src/client/components/ui/folder.vue @@ -153,10 +153,4 @@ export default defineComponent({ } } } - -._fitSide_ .ssazuxis { - > header { - padding: 0 16px; - } -} </style> diff --git a/src/client/components/ui/info.vue b/src/client/components/ui/info.vue index e16f2736f1..f6b2edf267 100644 --- a/src/client/components/ui/info.vue +++ b/src/client/components/ui/info.vue @@ -42,8 +42,4 @@ export default defineComponent({ margin-right: 4px; } } - -._fitSide_ .fpezltsf { - border-radius: 0; -} </style> diff --git a/src/client/components/ui/super-menu.vue b/src/client/components/ui/super-menu.vue index 6ab94d744d..195cc57326 100644 --- a/src/client/components/ui/super-menu.vue +++ b/src/client/components/ui/super-menu.vue @@ -50,9 +50,6 @@ export default defineComponent({ border-top: solid 0.5px var(--divider); } - margin-left: 16px; - margin-right: 16px; - > .title { font-size: 0.9em; opacity: 0.7; @@ -120,7 +117,7 @@ export default defineComponent({ > .items { display: grid; - grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); grid-gap: 8px; padding: 0 16px; diff --git a/src/client/components/ui/tooltip.vue b/src/client/components/ui/tooltip.vue index de8c02ad4a..c003895c14 100644 --- a/src/client/components/ui/tooltip.vue +++ b/src/client/components/ui/tooltip.vue @@ -1,6 +1,6 @@ <template> <transition name="tooltip" appear @after-leave="$emit('closed')"> - <div class="buebdbiu _acrylic _shadow" v-show="showing" ref="content"> + <div class="buebdbiu _acrylic _shadow" v-show="showing" ref="content" :style="{ maxWidth: maxWidth + 'px' }"> <slot>{{ text }}</slot> </div> </transition> @@ -21,7 +21,12 @@ export default defineComponent({ text: { type: String, required: false - } + }, + maxWidth: { + type: Number, + required: false, + default: 250, + }, }, emits: ['closed'], @@ -75,11 +80,12 @@ export default defineComponent({ .buebdbiu { position: absolute; z-index: 11000; - max-width: 240px; font-size: 0.8em; padding: 8px 12px; + box-sizing: border-box; text-align: center; border-radius: 4px; + border: solid 0.5px var(--divider); pointer-events: none; transform-origin: center bottom; } diff --git a/src/client/init.ts b/src/client/init.ts index c15374e49b..123d4020e1 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -166,8 +166,8 @@ const app = createApp(await ( ui === 'deck' ? import('@client/ui/deck.vue') : ui === 'desktop' ? import('@client/ui/desktop.vue') : ui === 'chat' ? import('@client/ui/chat/index.vue') : - ui === 'pope' ? import('@client/ui/universal.vue') : - import('@client/ui/default.vue') + ui === 'classic' ? import('@client/ui/classic.vue') : + import('@client/ui/universal.vue') ).then(x => x.default)); if (_DEV_) { diff --git a/src/client/menu.ts b/src/client/menu.ts index 0a9e2b5475..c884772a47 100644 --- a/src/client/menu.ts +++ b/src/client/menu.ts @@ -2,6 +2,7 @@ import { computed, ref } from 'vue'; import { search } from '@client/scripts/search'; import * as os from '@client/os'; import { i18n } from '@client/i18n'; +import { ui } from '@client/config'; import { $i } from './account'; import { unisonReload } from '@client/scripts/unison-reload'; import { router } from './router'; @@ -184,35 +185,40 @@ export const menuDef = { action: (ev) => { os.popupMenu([{ text: i18n.locale.default, + active: ui === 'default' || ui === null, action: () => { localStorage.setItem('ui', 'default'); unisonReload(); } }, { text: i18n.locale.deck, + active: ui === 'deck', action: () => { localStorage.setItem('ui', 'deck'); unisonReload(); } }, { - text: 'pope', + text: i18n.locale.classic, + active: ui === 'classic', action: () => { - localStorage.setItem('ui', 'pope'); + localStorage.setItem('ui', 'classic'); unisonReload(); } }, { text: 'Chat (β)', + active: ui === 'chat', action: () => { localStorage.setItem('ui', 'chat'); unisonReload(); } - }, { + }, /*{ text: i18n.locale.desktop + ' (β)', + active: ui === 'desktop', action: () => { localStorage.setItem('ui', 'desktop'); unisonReload(); } - }], ev.currentTarget || ev.target); + }*/], ev.currentTarget || ev.target); }, }, }; diff --git a/src/client/pages/admin/ads.vue b/src/client/pages/admin/ads.vue index e776f99a4c..4d39bb4e40 100644 --- a/src/client/pages/admin/ads.vue +++ b/src/client/pages/admin/ads.vue @@ -1,45 +1,42 @@ <template> -<div> - <MkHeader :info="header"/> - <div class="uqshojas"> - <section class="_card _gap ads" v-for="ad in ads"> - <div class="_content ad"> - <MkAd v-if="ad.url" :specify="ad"/> - <MkInput v-model="ad.url" type="url"> - <template #label>URL</template> - </MkInput> - <MkInput v-model="ad.imageUrl"> - <template #label>{{ $ts.imageUrl }}</template> - </MkInput> - <div style="margin: 32px 0;"> - <MkRadio v-model="ad.place" value="square">square</MkRadio> - <MkRadio v-model="ad.place" value="horizontal">horizontal</MkRadio> - <MkRadio v-model="ad.place" value="horizontal-big">horizontal-big</MkRadio> - </div> - <!-- - <div style="margin: 32px 0;"> - {{ $ts.priority }} - <MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio> - <MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio> - <MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio> - </div> - --> - <MkInput v-model="ad.ratio" type="number"> - <template #label>{{ $ts.ratio }}</template> - </MkInput> - <MkInput v-model="ad.expiresAt" type="date"> - <template #label>{{ $ts.expiration }}</template> - </MkInput> - <MkTextarea v-model="ad.memo"> - <template #label>{{ $ts.memo }}</template> - </MkTextarea> - <div class="buttons"> - <MkButton class="button" inline @click="save(ad)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> - <MkButton class="button" inline @click="remove(ad)" danger><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton> - </div> +<div class="uqshojas"> + <section class="_card _gap ads" v-for="ad in ads"> + <div class="_content ad"> + <MkAd v-if="ad.url" :specify="ad"/> + <MkInput v-model="ad.url" type="url"> + <template #label>URL</template> + </MkInput> + <MkInput v-model="ad.imageUrl"> + <template #label>{{ $ts.imageUrl }}</template> + </MkInput> + <div style="margin: 32px 0;"> + <MkRadio v-model="ad.place" value="square">square</MkRadio> + <MkRadio v-model="ad.place" value="horizontal">horizontal</MkRadio> + <MkRadio v-model="ad.place" value="horizontal-big">horizontal-big</MkRadio> </div> - </section> - </div> + <!-- + <div style="margin: 32px 0;"> + {{ $ts.priority }} + <MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio> + <MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio> + <MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio> + </div> + --> + <MkInput v-model="ad.ratio" type="number"> + <template #label>{{ $ts.ratio }}</template> + </MkInput> + <MkInput v-model="ad.expiresAt" type="date"> + <template #label>{{ $ts.expiration }}</template> + </MkInput> + <MkTextarea v-model="ad.memo"> + <template #label>{{ $ts.memo }}</template> + </MkTextarea> + <div class="buttons"> + <MkButton class="button" inline @click="save(ad)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> + <MkButton class="button" inline @click="remove(ad)" danger><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton> + </div> + </div> + </section> </div> </template> @@ -68,11 +65,6 @@ export default defineComponent({ title: this.$ts.ads, icon: 'fas fa-audio-description', bg: 'var(--bg)', - }, - header: { - title: this.$ts.ads, - icon: 'fas fa-audio-description', - bg: 'var(--bg)', actions: [{ asFullButton: true, icon: 'fas fa-plus', diff --git a/src/client/pages/admin/announcements.vue b/src/client/pages/admin/announcements.vue index 78637c095a..4ace515b0b 100644 --- a/src/client/pages/admin/announcements.vue +++ b/src/client/pages/admin/announcements.vue @@ -1,27 +1,23 @@ <template> -<div> - <MkHeader :info="header"/> - - <div class="ztgjmzrw"> - <section class="_card _gap announcements" v-for="announcement in announcements"> - <div class="_content announcement"> - <MkInput v-model="announcement.title"> - <template #label>{{ $ts.title }}</template> - </MkInput> - <MkTextarea v-model="announcement.text"> - <template #label>{{ $ts.text }}</template> - </MkTextarea> - <MkInput v-model="announcement.imageUrl"> - <template #label>{{ $ts.imageUrl }}</template> - </MkInput> - <p v-if="announcement.reads">{{ $t('nUsersRead', { n: announcement.reads }) }}</p> - <div class="buttons"> - <MkButton class="button" inline @click="save(announcement)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> - <MkButton class="button" inline @click="remove(announcement)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton> - </div> +<div class="ztgjmzrw"> + <section class="_card _gap announcements" v-for="announcement in announcements"> + <div class="_content announcement"> + <MkInput v-model="announcement.title"> + <template #label>{{ $ts.title }}</template> + </MkInput> + <MkTextarea v-model="announcement.text"> + <template #label>{{ $ts.text }}</template> + </MkTextarea> + <MkInput v-model="announcement.imageUrl"> + <template #label>{{ $ts.imageUrl }}</template> + </MkInput> + <p v-if="announcement.reads">{{ $t('nUsersRead', { n: announcement.reads }) }}</p> + <div class="buttons"> + <MkButton class="button" inline @click="save(announcement)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> + <MkButton class="button" inline @click="remove(announcement)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton> </div> - </section> - </div> + </div> + </section> </div> </template> @@ -48,11 +44,6 @@ export default defineComponent({ title: this.$ts.announcements, icon: 'fas fa-broadcast-tower', bg: 'var(--bg)', - }, - header: { - title: this.$ts.announcements, - icon: 'fas fa-broadcast-tower', - bg: 'var(--bg)', actions: [{ asFullButton: true, icon: 'fas fa-plus', diff --git a/src/client/pages/admin/emojis.vue b/src/client/pages/admin/emojis.vue index 4cd34b046d..80e0e00ba9 100644 --- a/src/client/pages/admin/emojis.vue +++ b/src/client/pages/admin/emojis.vue @@ -1,7 +1,5 @@ <template> <div class="ogwlenmc"> - <MkHeader :info="header"/> - <div class="local" v-if="tab === 'local'"> <MkInput v-model="query" :debounce="true" type="search" style="margin: var(--margin);"> <template #prefix><i class="fas fa-search"></i></template> @@ -71,12 +69,7 @@ export default defineComponent({ data() { return { - [symbols.PAGE_INFO]: { - title: this.$ts.customEmojis, - icon: 'fas fa-laugh', - bg: 'var(--bg)', - }, - header: computed(() => ({ + [symbols.PAGE_INFO]: computed(() => ({ title: this.$ts.customEmojis, icon: 'fas fa-laugh', bg: 'var(--bg)', diff --git a/src/client/pages/admin/index.vue b/src/client/pages/admin/index.vue index 416e68206c..cda3ab912a 100644 --- a/src/client/pages/admin/index.vue +++ b/src/client/pages/admin/index.vue @@ -3,17 +3,24 @@ <div class="nav" v-if="!narrow || page == null"> <MkHeader :info="header"></MkHeader> - <div class="lxpfedzu"> - <img :src="$instance.iconUrl || '/favicon.ico'" alt="" class="icon"/> - </div> + <MkSpacer :content-max="700"> + <div class="lxpfedzu"> + <div class="banner"> + <img :src="$instance.iconUrl || '/favicon.ico'" alt="" class="icon"/> + </div> - <MkInfo v-if="noMaintainerInformation" warn class="info">{{ $ts.noMaintainerInformationWarning }} <MkA to="/admin/settings" class="_link">{{ $ts.configure }}</MkA></MkInfo> - <MkInfo v-if="noBotProtection" warn class="info">{{ $ts.noBotProtectionWarning }} <MkA to="/admin/bot-protection" class="_link">{{ $ts.configure }}</MkA></MkInfo> + <MkInfo v-if="noMaintainerInformation" warn class="info">{{ $ts.noMaintainerInformationWarning }} <MkA to="/admin/settings" class="_link">{{ $ts.configure }}</MkA></MkInfo> + <MkInfo v-if="noBotProtection" warn class="info">{{ $ts.noBotProtectionWarning }} <MkA to="/admin/bot-protection" class="_link">{{ $ts.configure }}</MkA></MkInfo> - <MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu> + <MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu> + </div> + </MkSpacer> </div> <div class="main"> - <component :is="component" :key="page" @info="onInfo" v-bind="pageProps"/> + <MkStickyContainer> + <template #header><MkHeader v-if="childInfo && !childInfo.hideHeader" :info="childInfo"/></template> + <component :is="component" :key="page" @info="onInfo" v-bind="pageProps"/> + </MkStickyContainer> </div> </div> </template> @@ -41,6 +48,10 @@ export default defineComponent({ MkInfo, }, + provide: { + shouldOmitHeaderTitle: false, + }, + props: { initialPage: { type: String, @@ -50,17 +61,19 @@ export default defineComponent({ setup(props, context) { const indexInfo = { - title: i18n.locale.instance, + title: i18n.locale.controlPanel, icon: 'fas fa-cog', bg: 'var(--bg)', + hideHeader: true, }; const INFO = ref(indexInfo); + const childInfo = ref(null); const page = ref(props.initialPage); const narrow = ref(false); const view = ref(null); const el = ref(null); const onInfo = (viewInfo) => { - INFO.value = viewInfo; + childInfo.value = viewInfo; }; const pageProps = ref({}); @@ -306,7 +319,7 @@ export default defineComponent({ [symbols.PAGE_INFO]: INFO, menuDef, header: { - title: i18n.locale.controllPanel, + title: i18n.locale.controlPanel, }, noMaintainerInformation, noBotProtection, @@ -315,6 +328,7 @@ export default defineComponent({ view, el, onInfo, + childInfo, pageProps, component, invite, @@ -343,25 +357,26 @@ export default defineComponent({ > .main { flex: 1; min-width: 0; - --baseContentWidth: 100%; } } > .nav { - > .info { - margin: 16px; - } - } -} + .lxpfedzu { + > .info { + margin: 16px 0; + } -.lxpfedzu { - margin: 16px; + > .banner { + margin: 16px; - > .icon { - display: block; - margin: auto; - height: 42px; - border-radius: 8px; + > .icon { + display: block; + margin: auto; + height: 42px; + border-radius: 8px; + } + } + } } } </style> diff --git a/src/client/pages/admin/overview.vue b/src/client/pages/admin/overview.vue index bb9c10f106..ced200351e 100644 --- a/src/client/pages/admin/overview.vue +++ b/src/client/pages/admin/overview.vue @@ -1,71 +1,67 @@ <template> -<div> - <MkHeader :info="header"/> - - <div class="edbbcaef" v-size="{ max: [880] }"> - <div v-if="stats" class="cfcdecdf" style="margin: var(--margin)"> - <div class="number _panel"> - <div class="label">Users</div> - <div class="value _monospace"> - {{ number(stats.originalUsersCount) }} - <MkNumberDiff v-if="usersComparedToThePrevDay != null" class="diff" :value="usersComparedToThePrevDay" v-tooltip="$ts.dayOverDayChanges"><template #before>(</template><template #after>)</template></MkNumberDiff> - </div> - </div> - <div class="number _panel"> - <div class="label">Notes</div> - <div class="value _monospace"> - {{ number(stats.originalNotesCount) }} - <MkNumberDiff v-if="notesComparedToThePrevDay != null" class="diff" :value="notesComparedToThePrevDay" v-tooltip="$ts.dayOverDayChanges"><template #before>(</template><template #after>)</template></MkNumberDiff> - </div> +<div class="edbbcaef" v-size="{ max: [740] }"> + <div v-if="stats" class="cfcdecdf" style="margin: var(--margin)"> + <div class="number _panel"> + <div class="label">Users</div> + <div class="value _monospace"> + {{ number(stats.originalUsersCount) }} + <MkNumberDiff v-if="usersComparedToThePrevDay != null" class="diff" :value="usersComparedToThePrevDay" v-tooltip="$ts.dayOverDayChanges"><template #before>(</template><template #after>)</template></MkNumberDiff> </div> </div> - - <MkContainer :foldable="true" class="charts"> - <template #header><i class="fas fa-chart-bar"></i>{{ $ts.charts }}</template> - <div style="padding-top: 12px;"> - <MkInstanceStats :chart-limit="500" :detailed="true"/> + <div class="number _panel"> + <div class="label">Notes</div> + <div class="value _monospace"> + {{ number(stats.originalNotesCount) }} + <MkNumberDiff v-if="notesComparedToThePrevDay != null" class="diff" :value="notesComparedToThePrevDay" v-tooltip="$ts.dayOverDayChanges"><template #before>(</template><template #after>)</template></MkNumberDiff> </div> - </MkContainer> + </div> + </div> - <div class="queue"> - <MkContainer :foldable="true" :thin="true" class="deliver"> - <template #header>Queue: deliver</template> - <MkQueueChart :connection="queueStatsConnection" domain="deliver"/> - </MkContainer> - <MkContainer :foldable="true" :thin="true" class="inbox"> - <template #header>Queue: inbox</template> - <MkQueueChart :connection="queueStatsConnection" domain="inbox"/> - </MkContainer> + <MkContainer :foldable="true" class="charts"> + <template #header><i class="fas fa-chart-bar"></i>{{ $ts.charts }}</template> + <div style="padding-top: 12px;"> + <MkInstanceStats :chart-limit="500" :detailed="true"/> </div> + </MkContainer> + + <div class="queue"> + <MkContainer :foldable="true" :thin="true" class="deliver"> + <template #header>Queue: deliver</template> + <MkQueueChart :connection="queueStatsConnection" domain="deliver"/> + </MkContainer> + <MkContainer :foldable="true" :thin="true" class="inbox"> + <template #header>Queue: inbox</template> + <MkQueueChart :connection="queueStatsConnection" domain="inbox"/> + </MkContainer> + </div> - <!--<XMetrics/>--> + <!--<XMetrics/>--> - <MkFolder style="margin: var(--margin)"> - <template #header><i class="fas fa-info-circle"></i> {{ $ts.info }}</template> - <div class="cfcdecdf"> - <div class="number _panel"> - <div class="label">Misskey</div> - <div class="value _monospace">{{ version }}</div> - </div> - <div class="number _panel" v-if="serverInfo"> - <div class="label">Node.js</div> - <div class="value _monospace">{{ serverInfo.node }}</div> - </div> - <div class="number _panel" v-if="serverInfo"> - <div class="label">PostgreSQL</div> - <div class="value _monospace">{{ serverInfo.psql }}</div> - </div> - <div class="number _panel" v-if="serverInfo"> - <div class="label">Redis</div> - <div class="value _monospace">{{ serverInfo.redis }}</div> - </div> - <div class="number _panel"> - <div class="label">Vue</div> - <div class="value _monospace">{{ vueVersion }}</div> - </div> + <MkFolder style="margin: var(--margin)"> + <template #header><i class="fas fa-info-circle"></i> {{ $ts.info }}</template> + <div class="cfcdecdf"> + <div class="number _panel"> + <div class="label">Misskey</div> + <div class="value _monospace">{{ version }}</div> </div> - </MkFolder> - </div> + <div class="number _panel" v-if="serverInfo"> + <div class="label">Node.js</div> + <div class="value _monospace">{{ serverInfo.node }}</div> + </div> + <div class="number _panel" v-if="serverInfo"> + <div class="label">PostgreSQL</div> + <div class="value _monospace">{{ serverInfo.psql }}</div> + </div> + <div class="number _panel" v-if="serverInfo"> + <div class="label">Redis</div> + <div class="value _monospace">{{ serverInfo.redis }}</div> + </div> + <div class="number _panel"> + <div class="label">Vue</div> + <div class="value _monospace">{{ vueVersion }}</div> + </div> + </div> + </MkFolder> </div> </template> @@ -107,10 +103,6 @@ export default defineComponent({ icon: 'fas fa-tachometer-alt', bg: 'var(--bg)', }, - header: { - title: this.$ts.dashboard, - icon: 'fas fa-tachometer-alt', - }, version, vueVersion, url, @@ -225,12 +217,14 @@ export default defineComponent({ } } - &.max-width_800px { + &.max-width_740px { > .queue { display: block; > .deliver, > .inbox { + width: 100%; + &:not(:first-child) { margin-top: var(--margin); margin-left: 0; diff --git a/src/client/pages/admin/users.vue b/src/client/pages/admin/users.vue index f7f9306b70..37a54d2de3 100644 --- a/src/client/pages/admin/users.vue +++ b/src/client/pages/admin/users.vue @@ -1,7 +1,5 @@ <template> <div class="lknzcolw"> - <MkHeader :info="header"/> - <div class="users"> <div class="inputs"> <MkSelect v-model="sort" style="flex: 1;"> @@ -90,11 +88,6 @@ export default defineComponent({ title: this.$ts.users, icon: 'fas fa-users', bg: 'var(--bg)', - }, - header: { - title: this.$ts.users, - icon: 'fas fa-users', - bg: 'var(--bg)', actions: [{ icon: 'fas fa-search', text: this.$ts.search, @@ -109,7 +102,7 @@ export default defineComponent({ icon: 'fas fa-search', text: this.$ts.lookup, handler: this.lookupUser - }] + }], }, sort: '+createdAt', state: 'all', diff --git a/src/client/pages/announcements.vue b/src/client/pages/announcements.vue index 6a0cbd67ba..429d183d1e 100644 --- a/src/client/pages/announcements.vue +++ b/src/client/pages/announcements.vue @@ -1,21 +1,18 @@ <template> -<div> - <MkHeader :info="header"/> - <div class="_section"> - <MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content"> - <section class="_card announcement _gap" v-for="(announcement, i) in items" :key="announcement.id"> - <div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div> - <div class="_content"> - <Mfm :text="announcement.text"/> - <img v-if="announcement.imageUrl" :src="announcement.imageUrl"/> - </div> - <div class="_footer" v-if="$i && !announcement.isRead"> - <MkButton @click="read(items, announcement, i)" primary><i class="fas fa-check"></i> {{ $ts.gotIt }}</MkButton> - </div> - </section> - </MkPagination> - </div> -</div> +<MkSpacer :content-max="800"> + <MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content"> + <section class="_card announcement" v-for="(announcement, i) in items" :key="announcement.id"> + <div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div> + <div class="_content"> + <Mfm :text="announcement.text"/> + <img v-if="announcement.imageUrl" :src="announcement.imageUrl"/> + </div> + <div class="_footer" v-if="$i && !announcement.isRead"> + <MkButton @click="read(items, announcement, i)" primary><i class="fas fa-check"></i> {{ $ts.gotIt }}</MkButton> + </div> + </section> + </MkPagination> +</MkSpacer> </template> <script lang="ts"> @@ -38,11 +35,6 @@ export default defineComponent({ icon: 'fas fa-broadcast-tower', bg: 'var(--bg)', }, - header: { - title: this.$ts.announcements, - icon: 'fas fa-broadcast-tower', - bg: 'var(--bg)', - }, pagination: { endpoint: 'announcements', limit: 10, @@ -66,6 +58,10 @@ export default defineComponent({ <style lang="scss" scoped> .ruryvtyk { > .announcement { + &:not(:last-child) { + margin-bottom: var(--margin); + } + > ._content { > img { display: block; diff --git a/src/client/pages/emojis.vue b/src/client/pages/emojis.vue index d61fd25d3c..8918de2338 100644 --- a/src/client/pages/emojis.vue +++ b/src/client/pages/emojis.vue @@ -1,9 +1,6 @@ <template> -<div> - <MkHeader :info="header"/> - <div :class="$style.root"> - <XCategory v-if="tab === 'category'"/> - </div> +<div :class="$style.root"> + <XCategory v-if="tab === 'category'"/> </div> </template> @@ -25,11 +22,6 @@ export default defineComponent({ icon: 'fas fa-laugh', bg: 'var(--bg)', })), - header: computed(() => ({ - title: this.$ts.customEmojis, - icon: 'fas fa-laugh', - bg: 'var(--bg)', - })), tab: 'category', } }, diff --git a/src/client/pages/explore.vue b/src/client/pages/explore.vue index 6f304877b7..a77b4e53c3 100644 --- a/src/client/pages/explore.vue +++ b/src/client/pages/explore.vue @@ -1,7 +1,5 @@ <template> <div> - <MkHeader :info="header"/> - <MkSpacer :content-max="1200"> <div class="lznhrdub"> <div v-if="tab === 'local'"> @@ -110,13 +108,7 @@ export default defineComponent({ data() { return { - [symbols.PAGE_INFO]: { - title: this.$ts.explore, - icon: 'fas fa-hashtag', - bg: 'var(--bg)', - }, - tab: 'local', - header: computed(() => ({ + [symbols.PAGE_INFO]: computed(() => ({ title: this.$ts.explore, icon: 'fas fa-hashtag', bg: 'var(--bg)', @@ -134,6 +126,7 @@ export default defineComponent({ onClick: () => { this.tab = 'search'; }, },] })), + tab: 'local', pinnedUsers: { endpoint: 'pinned-users' }, popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: { state: 'alive', diff --git a/src/client/pages/favorites.vue b/src/client/pages/favorites.vue index bed78d1dbe..f13723c2d1 100644 --- a/src/client/pages/favorites.vue +++ b/src/client/pages/favorites.vue @@ -1,10 +1,7 @@ <template> -<div> - <MkHeader :info="header"/> - <div class="jmelgwjh"> - <div class="body"> - <XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/> - </div> +<div class="jmelgwjh"> + <div class="body"> + <XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/> </div> </div> </template> @@ -28,11 +25,6 @@ export default defineComponent({ icon: 'fas fa-star', bg: 'var(--bg)', }, - header: { - title: this.$ts.favorites, - icon: 'fas fa-star', - bg: 'var(--bg)', - }, pagination: { endpoint: 'i/favorites', limit: 10, diff --git a/src/client/pages/featured.vue b/src/client/pages/featured.vue index 5d8da54541..50df26bfb1 100644 --- a/src/client/pages/featured.vue +++ b/src/client/pages/featured.vue @@ -1,10 +1,7 @@ <template> -<div> - <MkHeader :info="header"/> - <div class="_section"> - <XNotes class="_content" ref="notes" :pagination="pagination" @before="before" @after="after"/> - </div> -</div> +<MkSpacer :content-max="800"> + <XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/> +</MkSpacer> </template> <script lang="ts"> @@ -25,11 +22,6 @@ export default defineComponent({ icon: 'fas fa-fire-alt', bg: 'var(--bg)', }, - header: { - title: this.$ts.featured, - icon: 'fas fa-fire-alt', - bg: 'var(--bg)', - }, pagination: { endpoint: 'notes/featured', limit: 10, diff --git a/src/client/pages/federation.vue b/src/client/pages/federation.vue index ae0aed4cc7..eae6a05367 100644 --- a/src/client/pages/federation.vue +++ b/src/client/pages/federation.vue @@ -1,98 +1,95 @@ <template> -<div> - <MkHeader :info="header"/> - <div class="taeiyria"> - <div class="query"> - <MkInput v-model="host" :debounce="true" class=""> - <template #prefix><i class="fas fa-search"></i></template> - <template #label>{{ $ts.host }}</template> - </MkInput> - <div class="_inputSplit"> - <MkSelect v-model="state"> - <template #label>{{ $ts.state }}</template> - <option value="all">{{ $ts.all }}</option> - <option value="federating">{{ $ts.federating }}</option> - <option value="subscribing">{{ $ts.subscribing }}</option> - <option value="publishing">{{ $ts.publishing }}</option> - <option value="suspended">{{ $ts.suspended }}</option> - <option value="blocked">{{ $ts.blocked }}</option> - <option value="notResponding">{{ $ts.notResponding }}</option> - </MkSelect> - <MkSelect v-model="sort"> - <template #label>{{ $ts.sort }}</template> - <option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option> - <option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option> - <option value="+notes">{{ $ts.notes }} ({{ $ts.descendingOrder }})</option> - <option value="-notes">{{ $ts.notes }} ({{ $ts.ascendingOrder }})</option> - <option value="+users">{{ $ts.users }} ({{ $ts.descendingOrder }})</option> - <option value="-users">{{ $ts.users }} ({{ $ts.ascendingOrder }})</option> - <option value="+following">{{ $ts.following }} ({{ $ts.descendingOrder }})</option> - <option value="-following">{{ $ts.following }} ({{ $ts.ascendingOrder }})</option> - <option value="+followers">{{ $ts.followers }} ({{ $ts.descendingOrder }})</option> - <option value="-followers">{{ $ts.followers }} ({{ $ts.ascendingOrder }})</option> - <option value="+caughtAt">{{ $ts.registeredAt }} ({{ $ts.descendingOrder }})</option> - <option value="-caughtAt">{{ $ts.registeredAt }} ({{ $ts.ascendingOrder }})</option> - <option value="+lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.descendingOrder }})</option> - <option value="-lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.ascendingOrder }})</option> - <option value="+driveUsage">{{ $ts.driveUsage }} ({{ $ts.descendingOrder }})</option> - <option value="-driveUsage">{{ $ts.driveUsage }} ({{ $ts.ascendingOrder }})</option> - <option value="+driveFiles">{{ $ts.driveFilesCount }} ({{ $ts.descendingOrder }})</option> - <option value="-driveFiles">{{ $ts.driveFilesCount }} ({{ $ts.ascendingOrder }})</option> - </MkSelect> - </div> +<div class="taeiyria"> + <div class="query"> + <MkInput v-model="host" :debounce="true" class=""> + <template #prefix><i class="fas fa-search"></i></template> + <template #label>{{ $ts.host }}</template> + </MkInput> + <div class="_inputSplit"> + <MkSelect v-model="state"> + <template #label>{{ $ts.state }}</template> + <option value="all">{{ $ts.all }}</option> + <option value="federating">{{ $ts.federating }}</option> + <option value="subscribing">{{ $ts.subscribing }}</option> + <option value="publishing">{{ $ts.publishing }}</option> + <option value="suspended">{{ $ts.suspended }}</option> + <option value="blocked">{{ $ts.blocked }}</option> + <option value="notResponding">{{ $ts.notResponding }}</option> + </MkSelect> + <MkSelect v-model="sort"> + <template #label>{{ $ts.sort }}</template> + <option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option> + <option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option> + <option value="+notes">{{ $ts.notes }} ({{ $ts.descendingOrder }})</option> + <option value="-notes">{{ $ts.notes }} ({{ $ts.ascendingOrder }})</option> + <option value="+users">{{ $ts.users }} ({{ $ts.descendingOrder }})</option> + <option value="-users">{{ $ts.users }} ({{ $ts.ascendingOrder }})</option> + <option value="+following">{{ $ts.following }} ({{ $ts.descendingOrder }})</option> + <option value="-following">{{ $ts.following }} ({{ $ts.ascendingOrder }})</option> + <option value="+followers">{{ $ts.followers }} ({{ $ts.descendingOrder }})</option> + <option value="-followers">{{ $ts.followers }} ({{ $ts.ascendingOrder }})</option> + <option value="+caughtAt">{{ $ts.registeredAt }} ({{ $ts.descendingOrder }})</option> + <option value="-caughtAt">{{ $ts.registeredAt }} ({{ $ts.ascendingOrder }})</option> + <option value="+lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.descendingOrder }})</option> + <option value="-lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.ascendingOrder }})</option> + <option value="+driveUsage">{{ $ts.driveUsage }} ({{ $ts.descendingOrder }})</option> + <option value="-driveUsage">{{ $ts.driveUsage }} ({{ $ts.ascendingOrder }})</option> + <option value="+driveFiles">{{ $ts.driveFilesCount }} ({{ $ts.descendingOrder }})</option> + <option value="-driveFiles">{{ $ts.driveFilesCount }} ({{ $ts.ascendingOrder }})</option> + </MkSelect> </div> + </div> - <MkPagination :pagination="pagination" #default="{items}" ref="instances" :key="host + state"> - <div class="dqokceoi"> - <MkA class="instance" v-for="instance in items" :key="instance.id" :to="`/instance-info/${instance.host}`"> - <div class="host"><img :src="instance.faviconUrl">{{ instance.host }}</div> - <div class="table"> - <div class="cell"> - <div class="key">{{ $ts.registeredAt }}</div> - <div class="value"><MkTime :time="instance.caughtAt"/></div> - </div> - <div class="cell"> - <div class="key">{{ $ts.software }}</div> - <div class="value">{{ instance.softwareName || `(${$ts.unknown})` }}</div> - </div> - <div class="cell"> - <div class="key">{{ $ts.version }}</div> - <div class="value">{{ instance.softwareVersion || `(${$ts.unknown})` }}</div> - </div> - <div class="cell"> - <div class="key">{{ $ts.users }}</div> - <div class="value">{{ instance.usersCount }}</div> - </div> - <div class="cell"> - <div class="key">{{ $ts.notes }}</div> - <div class="value">{{ instance.notesCount }}</div> - </div> - <div class="cell"> - <div class="key">{{ $ts.sent }}</div> - <div class="value"><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></div> - </div> - <div class="cell"> - <div class="key">{{ $ts.received }}</div> - <div class="value"><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></div> - </div> + <MkPagination :pagination="pagination" #default="{items}" ref="instances" :key="host + state"> + <div class="dqokceoi"> + <MkA class="instance" v-for="instance in items" :key="instance.id" :to="`/instance-info/${instance.host}`"> + <div class="host"><img :src="instance.faviconUrl">{{ instance.host }}</div> + <div class="table"> + <div class="cell"> + <div class="key">{{ $ts.registeredAt }}</div> + <div class="value"><MkTime :time="instance.caughtAt"/></div> </div> - <div class="footer"> - <span class="status" :class="getStatus(instance)">{{ getStatus(instance) }}</span> - <span class="pubSub"> - <span class="sub" v-if="instance.followersCount > 0"><i class="fas fa-caret-down icon"></i>Sub</span> - <span class="sub" v-else><i class="fas fa-caret-down icon"></i>-</span> - <span class="pub" v-if="instance.followingCount > 0"><i class="fas fa-caret-up icon"></i>Pub</span> - <span class="pub" v-else><i class="fas fa-caret-up icon"></i>-</span> - </span> - <span class="right"> - <span class="latestStatus">{{ instance.latestStatus || '-' }}</span> - <span class="lastCommunicatedAt"><MkTime :time="instance.lastCommunicatedAt"/></span> - </span> + <div class="cell"> + <div class="key">{{ $ts.software }}</div> + <div class="value">{{ instance.softwareName || `(${$ts.unknown})` }}</div> </div> - </MkA> - </div> - </MkPagination> - </div> + <div class="cell"> + <div class="key">{{ $ts.version }}</div> + <div class="value">{{ instance.softwareVersion || `(${$ts.unknown})` }}</div> + </div> + <div class="cell"> + <div class="key">{{ $ts.users }}</div> + <div class="value">{{ instance.usersCount }}</div> + </div> + <div class="cell"> + <div class="key">{{ $ts.notes }}</div> + <div class="value">{{ instance.notesCount }}</div> + </div> + <div class="cell"> + <div class="key">{{ $ts.sent }}</div> + <div class="value"><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></div> + </div> + <div class="cell"> + <div class="key">{{ $ts.received }}</div> + <div class="value"><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></div> + </div> + </div> + <div class="footer"> + <span class="status" :class="getStatus(instance)">{{ getStatus(instance) }}</span> + <span class="pubSub"> + <span class="sub" v-if="instance.followersCount > 0"><i class="fas fa-caret-down icon"></i>Sub</span> + <span class="sub" v-else><i class="fas fa-caret-down icon"></i>-</span> + <span class="pub" v-if="instance.followingCount > 0"><i class="fas fa-caret-up icon"></i>Pub</span> + <span class="pub" v-else><i class="fas fa-caret-up icon"></i>-</span> + </span> + <span class="right"> + <span class="latestStatus">{{ instance.latestStatus || '-' }}</span> + <span class="lastCommunicatedAt"><MkTime :time="instance.lastCommunicatedAt"/></span> + </span> + </div> + </MkA> + </div> + </MkPagination> </div> </template> @@ -122,11 +119,6 @@ export default defineComponent({ icon: 'fas fa-globe', bg: 'var(--bg)', }, - header: { - title: this.$ts.federation, - icon: 'fas fa-globe', - bg: 'var(--bg)', - }, host: '', state: 'federating', sort: '+pubSub', diff --git a/src/client/pages/mentions.vue b/src/client/pages/mentions.vue index e1d2f096e1..04682a856a 100644 --- a/src/client/pages/mentions.vue +++ b/src/client/pages/mentions.vue @@ -1,10 +1,7 @@ <template> -<div> - <MkHeader :info="header"/> - <div class="_section"> - <XNotes class="_content" :pagination="pagination" @before="before()" @after="after()"/> - </div> -</div> +<MkSpacer :content-max="800"> + <XNotes :pagination="pagination" @before="before()" @after="after()"/> +</MkSpacer> </template> <script lang="ts"> @@ -25,11 +22,6 @@ export default defineComponent({ icon: 'fas fa-at', bg: 'var(--bg)', }, - header: { - title: this.$ts.mentions, - icon: 'fas fa-at', - bg: 'var(--bg)', - }, pagination: { endpoint: 'notes/mentions', limit: 10, diff --git a/src/client/pages/messages.vue b/src/client/pages/messages.vue index f4c68daab9..e3d668cf45 100644 --- a/src/client/pages/messages.vue +++ b/src/client/pages/messages.vue @@ -1,10 +1,7 @@ <template> -<div> - <MkHeader :info="header"/> - <div> - <XNotes :pagination="pagination" @before="before()" @after="after()"/> - </div> -</div> +<MkSpacer :content-max="800"> + <XNotes :pagination="pagination" @before="before()" @after="after()"/> +</MkSpacer> </template> <script lang="ts"> @@ -25,11 +22,6 @@ export default defineComponent({ icon: 'fas fa-envelope', bg: 'var(--bg)', }, - header: { - title: this.$ts.directNotes, - icon: 'fas fa-envelope', - bg: 'var(--bg)', - }, pagination: { endpoint: 'notes/mentions', limit: 10, diff --git a/src/client/pages/messaging/index.vue b/src/client/pages/messaging/index.vue index fef3b76e10..5b4fd51e55 100644 --- a/src/client/pages/messaging/index.vue +++ b/src/client/pages/messaging/index.vue @@ -1,8 +1,6 @@ <template> -<div> - <MkHeader :info="header"/> - - <div class="yweeujhr _root" v-size="{ max: [400] }"> +<MkSpacer :content-max="800"> + <div class="yweeujhr" v-size="{ max: [400] }"> <MkButton @click="start" primary class="start"><i class="fas fa-plus"></i> {{ $ts.startMessaging }}</MkButton> <div class="history" v-if="messages.length > 0"> @@ -37,7 +35,7 @@ </div> <MkLoading v-if="fetching"/> </div> -</div> +</MkSpacer> </template> <script lang="ts"> @@ -60,11 +58,6 @@ export default defineComponent({ icon: 'fas fa-comments', bg: 'var(--bg)', }, - header: { - title: this.$ts.messaging, - icon: 'fas fa-comments', - bg: 'var(--bg)', - }, fetching: true, moreFetching: false, messages: [], @@ -177,7 +170,7 @@ export default defineComponent({ .yweeujhr { > .start { - margin: var(--margin) auto var(--margin) auto; + margin: 0 auto var(--margin) auto; } > .history { diff --git a/src/client/pages/my-lists/index.vue b/src/client/pages/my-lists/index.vue index b0e9bf9d54..687e9e630e 100644 --- a/src/client/pages/my-lists/index.vue +++ b/src/client/pages/my-lists/index.vue @@ -1,16 +1,13 @@ <template> -<div> - <MkHeader :info="header"/> - <div class="qkcjvfiv"> - <MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton> +<div class="qkcjvfiv"> + <MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton> - <MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list"> - <MkA v-for="list in items" :key="list.id" class="list _panel" :to="`/my/lists/${ list.id }`"> - <div class="name">{{ list.name }}</div> - <MkAvatars :user-ids="list.userIds"/> - </MkA> - </MkPagination> - </div> + <MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list"> + <MkA v-for="list in items" :key="list.id" class="list _panel" :to="`/my/lists/${ list.id }`"> + <div class="name">{{ list.name }}</div> + <MkAvatars :user-ids="list.userIds"/> + </MkA> + </MkPagination> </div> </template> @@ -35,15 +32,10 @@ export default defineComponent({ title: this.$ts.manageLists, icon: 'fas fa-list-ul', bg: 'var(--bg)', - }, - header: { - title: this.$ts.manageLists, - icon: 'fas fa-list-ul', - bg: 'var(--bg)', action: { icon: 'fas fa-plus', handler: this.create - } + }, }, pagination: { endpoint: 'users/lists/list', diff --git a/src/client/pages/my-lists/list.vue b/src/client/pages/my-lists/list.vue index 27c979bc88..049d370b4e 100644 --- a/src/client/pages/my-lists/list.vue +++ b/src/client/pages/my-lists/list.vue @@ -1,37 +1,34 @@ <template> -<div> - <MkHeader v-if="header" :info="header"/> - <div class="mk-list-page"> - <transition name="zoom" mode="out-in"> - <div v-if="list" class="_section"> - <div class="_content"> - <MkButton inline @click="addUser()">{{ $ts.addUser }}</MkButton> - <MkButton inline @click="renameList()">{{ $ts.rename }}</MkButton> - <MkButton inline @click="deleteList()">{{ $ts.delete }}</MkButton> - </div> +<div class="mk-list-page"> + <transition name="zoom" mode="out-in"> + <div v-if="list" class="_section"> + <div class="_content"> + <MkButton inline @click="addUser()">{{ $ts.addUser }}</MkButton> + <MkButton inline @click="renameList()">{{ $ts.rename }}</MkButton> + <MkButton inline @click="deleteList()">{{ $ts.delete }}</MkButton> </div> - </transition> + </div> + </transition> - <transition name="zoom" mode="out-in"> - <div v-if="list" class="_section members _gap"> - <div class="_title">{{ $ts.members }}</div> - <div class="_content"> - <div class="users"> - <div class="user _panel" v-for="user in users" :key="user.id"> - <MkAvatar :user="user" class="avatar" :show-indicator="true"/> - <div class="body"> - <MkUserName :user="user" class="name"/> - <MkAcct :user="user" class="acct"/> - </div> - <div class="action"> - <button class="_button" @click="removeUser(user)"><i class="fas fa-times"></i></button> - </div> + <transition name="zoom" mode="out-in"> + <div v-if="list" class="_section members _gap"> + <div class="_title">{{ $ts.members }}</div> + <div class="_content"> + <div class="users"> + <div class="user _panel" v-for="user in users" :key="user.id"> + <MkAvatar :user="user" class="avatar" :show-indicator="true"/> + <div class="body"> + <MkUserName :user="user" class="name"/> + <MkAcct :user="user" class="acct"/> + </div> + <div class="action"> + <button class="_button" @click="removeUser(user)"><i class="fas fa-times"></i></button> </div> </div> </div> </div> - </transition> - </div> + </div> + </transition> </div> </template> @@ -53,10 +50,6 @@ export default defineComponent({ title: this.list.name, icon: 'fas fa-list-ul', } : null), - header: computed(() => this.list ? { - title: this.list.name, - icon: 'fas fa-list-ul', - } : null), list: null, users: [], }; diff --git a/src/client/pages/note.vue b/src/client/pages/note.vue index fe85d7364e..8e95430d67 100644 --- a/src/client/pages/note.vue +++ b/src/client/pages/note.vue @@ -1,6 +1,6 @@ <template> -<div class="fcuexfpr"> - <div class="_root"> +<MkSpacer :content-max="800"> + <div class="fcuexfpr"> <transition name="fade" mode="out-in"> <div v-if="note" class="note"> <div class="_gap" v-if="showNext"> @@ -34,7 +34,7 @@ <MkLoading v-else/> </transition> </div> -</div> +</MkSpacer> </template> <script lang="ts"> @@ -153,54 +153,52 @@ export default defineComponent({ .fcuexfpr { background: var(--bg); - > ._root { - > .note { - > .main { - > .load { - min-width: 0; - margin: 0 auto; - border-radius: 999px; + > .note { + > .main { + > .load { + min-width: 0; + margin: 0 auto; + border-radius: 999px; - &.next { - margin-bottom: var(--margin); - } + &.next { + margin-bottom: var(--margin); + } - &.prev { - margin-top: var(--margin); - } + &.prev { + margin-top: var(--margin); } + } + > .note { > .note { - > .note { - border-radius: var(--radius); - background: var(--panel); - } + border-radius: var(--radius); + background: var(--panel); } + } - > .clips { - > .title { - font-weight: bold; - padding: 12px; - } + > .clips { + > .title { + font-weight: bold; + padding: 12px; + } - > .item { - display: block; - padding: 16px; + > .item { + display: block; + padding: 16px; - > .description { - padding: 8px 0; - } + > .description { + padding: 8px 0; + } - > .user { - $height: 32px; - padding-top: 16px; - border-top: solid 0.5px var(--divider); - line-height: $height; + > .user { + $height: 32px; + padding-top: 16px; + border-top: solid 0.5px var(--divider); + line-height: $height; - > .avatar { - width: $height; - height: $height; - } + > .avatar { + width: $height; + height: $height; } } } diff --git a/src/client/pages/notifications.vue b/src/client/pages/notifications.vue index 049d057d02..8d6adec48d 100644 --- a/src/client/pages/notifications.vue +++ b/src/client/pages/notifications.vue @@ -1,12 +1,9 @@ <template> -<div> - <MkHeader :info="header"/> - <MkSpacer :content-max="800"> - <div class="clupoqwt"> - <XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/> - </div> - </MkSpacer> -</div> +<MkSpacer :content-max="800"> + <div class="clupoqwt"> + <XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/> + </div> +</MkSpacer> </template> <script lang="ts"> @@ -24,14 +21,7 @@ export default defineComponent({ data() { return { - [symbols.PAGE_INFO]: { - title: this.$ts.notifications, - icon: 'fas fa-bell', - bg: 'var(--bg)', - }, - tab: 'all', - includeTypes: null, - header: computed(() => ({ + [symbols.PAGE_INFO]: computed(() => ({ title: this.$ts.notifications, icon: 'fas fa-bell', bg: 'var(--bg)', @@ -57,6 +47,8 @@ export default defineComponent({ onClick: () => { this.tab = 'unread'; }, },] })), + tab: 'all', + includeTypes: null, }; }, diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue index e04039e634..aefcc14564 100644 --- a/src/client/pages/page-editor/page-editor.vue +++ b/src/client/pages/page-editor/page-editor.vue @@ -1,82 +1,78 @@ <template> <div> - <MkHeader :info="header"/> - - <div class="_root"> - <div class="jqqmcavi" style="margin: 16px;"> - <MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton> - <MkButton inline @click="save" primary class="button" v-if="!readonly"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> - <MkButton inline @click="duplicate" class="button" v-if="pageId"><i class="fas fa-copy"></i> {{ $ts.duplicate }}</MkButton> - <MkButton inline @click="del" class="button" v-if="pageId && !readonly" danger><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton> - </div> + <div class="jqqmcavi" style="margin: 16px;"> + <MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton> + <MkButton inline @click="save" primary class="button" v-if="!readonly"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> + <MkButton inline @click="duplicate" class="button" v-if="pageId"><i class="fas fa-copy"></i> {{ $ts.duplicate }}</MkButton> + <MkButton inline @click="del" class="button" v-if="pageId && !readonly" danger><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton> + </div> - <div v-if="tab === 'settings'"> - <div style="padding: 16px;" class="_formRoot"> - <MkInput v-model="title" class="_formBlock"> - <template #label>{{ $ts._pages.title }}</template> - </MkInput> + <div v-if="tab === 'settings'"> + <div style="padding: 16px;" class="_formRoot"> + <MkInput v-model="title" class="_formBlock"> + <template #label>{{ $ts._pages.title }}</template> + </MkInput> - <MkInput v-model="summary" class="_formBlock"> - <template #label>{{ $ts._pages.summary }}</template> - </MkInput> + <MkInput v-model="summary" class="_formBlock"> + <template #label>{{ $ts._pages.summary }}</template> + </MkInput> - <MkInput v-model="name" class="_formBlock"> - <template #prefix>{{ url }}/@{{ author.username }}/pages/</template> - <template #label>{{ $ts._pages.url }}</template> - </MkInput> + <MkInput v-model="name" class="_formBlock"> + <template #prefix>{{ url }}/@{{ author.username }}/pages/</template> + <template #label>{{ $ts._pages.url }}</template> + </MkInput> - <MkSwitch v-model="alignCenter" class="_formBlock">{{ $ts._pages.alignCenter }}</MkSwitch> + <MkSwitch v-model="alignCenter" class="_formBlock">{{ $ts._pages.alignCenter }}</MkSwitch> - <MkSelect v-model="font" class="_formBlock"> - <template #label>{{ $ts._pages.font }}</template> - <option value="serif">{{ $ts._pages.fontSerif }}</option> - <option value="sans-serif">{{ $ts._pages.fontSansSerif }}</option> - </MkSelect> + <MkSelect v-model="font" class="_formBlock"> + <template #label>{{ $ts._pages.font }}</template> + <option value="serif">{{ $ts._pages.fontSerif }}</option> + <option value="sans-serif">{{ $ts._pages.fontSansSerif }}</option> + </MkSelect> - <MkSwitch v-model="hideTitleWhenPinned" class="_formBlock">{{ $ts._pages.hideTitleWhenPinned }}</MkSwitch> + <MkSwitch v-model="hideTitleWhenPinned" class="_formBlock">{{ $ts._pages.hideTitleWhenPinned }}</MkSwitch> - <div class="eyeCatch"> - <MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><i class="fas fa-plus"></i> {{ $ts._pages.eyeCatchingImageSet }}</MkButton> - <div v-else-if="eyeCatchingImage"> - <img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/> - <MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><i class="fas fa-trash-alt"></i> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton> - </div> + <div class="eyeCatch"> + <MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><i class="fas fa-plus"></i> {{ $ts._pages.eyeCatchingImageSet }}</MkButton> + <div v-else-if="eyeCatchingImage"> + <img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/> + <MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><i class="fas fa-trash-alt"></i> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton> </div> </div> </div> + </div> - <div v-else-if="tab === 'contents'"> - <div style="padding: 16px;"> - <XBlocks class="content" v-model="content" :hpml="hpml"/> + <div v-else-if="tab === 'contents'"> + <div style="padding: 16px;"> + <XBlocks class="content" v-model="content" :hpml="hpml"/> - <MkButton @click="add()" v-if="!readonly"><i class="fas fa-plus"></i></MkButton> - </div> + <MkButton @click="add()" v-if="!readonly"><i class="fas fa-plus"></i></MkButton> </div> + </div> - <div v-else-if="tab === 'variables'"> - <div class="qmuvgica"> - <XDraggable tag="div" class="variables" v-show="variables.length > 0" v-model="variables" item-key="name" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5"> - <template #item="{element}"> - <XVariable - :modelValue="element" - :removable="true" - @remove="() => removeVariable(element)" - :hpml="hpml" - :name="element.name" - :title="element.name" - :draggable="true" - /> - </template> - </XDraggable> + <div v-else-if="tab === 'variables'"> + <div class="qmuvgica"> + <XDraggable tag="div" class="variables" v-show="variables.length > 0" v-model="variables" item-key="name" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5"> + <template #item="{element}"> + <XVariable + :modelValue="element" + :removable="true" + @remove="() => removeVariable(element)" + :hpml="hpml" + :name="element.name" + :title="element.name" + :draggable="true" + /> + </template> + </XDraggable> - <MkButton @click="addVariable()" class="add" v-if="!readonly"><i class="fas fa-plus"></i></MkButton> - </div> + <MkButton @click="addVariable()" class="add" v-if="!readonly"><i class="fas fa-plus"></i></MkButton> </div> + </div> - <div v-else-if="tab === 'script'"> - <div> - <MkTextarea class="_code" v-model="script"/> - </div> + <div v-else-if="tab === 'script'"> + <div> + <MkTextarea class="_code" v-model="script"/> </div> </div> </div> @@ -142,21 +138,6 @@ export default defineComponent({ title: title, icon: 'fas fa-pencil-alt', bg: 'var(--bg)', - }; - }), - tab: 'settings', - header: computed(() => { - let title = this.$ts._pages.newPage; - if (this.initPageId) { - title = this.$ts._pages.editPage; - } - else if (this.initPageName && this.initUser) { - title = this.$ts._pages.readPage; - } - return { - title: title, - icon: 'fas fa-pencil-alt', - bg: 'var(--bg)', tabs: [{ active: this.tab === 'settings', title: this.$ts._pages.pageSetting, @@ -177,9 +158,10 @@ export default defineComponent({ title: this.$ts.script, icon: 'fas fa-code', onClick: () => { this.tab = 'script'; }, - }] + }], }; }), + tab: 'settings', author: this.$i, readonly: false, page: null, diff --git a/src/client/pages/page.vue b/src/client/pages/page.vue index b8d7507363..3ea687a35d 100644 --- a/src/client/pages/page.vue +++ b/src/client/pages/page.vue @@ -1,65 +1,61 @@ <template> <div> - <MkHeader :info="header"/> - - <div class="_root"> - <transition name="fade" mode="out-in"> - <div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }"> - <div class="_block main"> - <!-- - <div class="header"> - <h1>{{ page.title }}</h1> - </div> - --> - <div class="banner"> - <img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/> - </div> - <div class="content"> - <XPage :page="page"/> - </div> - <div class="actions"> - <div class="like"> - <MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton> - <MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton> - </div> - <div class="other"> - <button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button> - <button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button> - </div> + <transition name="fade" mode="out-in"> + <div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }"> + <div class="_block main"> + <!-- + <div class="header"> + <h1>{{ page.title }}</h1> + </div> + --> + <div class="banner"> + <img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/> + </div> + <div class="content"> + <XPage :page="page"/> + </div> + <div class="actions"> + <div class="like"> + <MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton> + <MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton> </div> - <div class="user"> - <MkAvatar :user="page.user" class="avatar"/> - <div class="name"> - <MkUserName :user="page.user" style="display: block;"/> - <MkAcct :user="page.user"/> - </div> - <MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/> + <div class="other"> + <button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button> + <button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button> </div> - <div class="links"> - <MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA> - <template v-if="$i && $i.id === page.userId"> - <MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA> - <button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button> - <button v-else @click="pin(true)" class="link _textButton">{{ $ts.pin }}</button> - </template> + </div> + <div class="user"> + <MkAvatar :user="page.user" class="avatar"/> + <div class="name"> + <MkUserName :user="page.user" style="display: block;"/> + <MkAcct :user="page.user"/> </div> + <MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/> </div> - <div class="footer"> - <div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div> - <div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div> + <div class="links"> + <MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA> + <template v-if="$i && $i.id === page.userId"> + <MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA> + <button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button> + <button v-else @click="pin(true)" class="link _textButton">{{ $ts.pin }}</button> + </template> </div> - <MkAd :prefer="['horizontal', 'horizontal-big']"/> - <MkContainer :max-height="300" :foldable="true" class="other"> - <template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template> - <MkPagination :pagination="otherPostsPagination" #default="{items}"> - <MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/> - </MkPagination> - </MkContainer> </div> - <MkError v-else-if="error" @retry="fetch()"/> - <MkLoading v-else/> - </transition> - </div> + <div class="footer"> + <div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div> + <div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div> + </div> + <MkAd :prefer="['horizontal', 'horizontal-big']"/> + <MkContainer :max-height="300" :foldable="true" class="other"> + <template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template> + <MkPagination :pagination="otherPostsPagination" #default="{items}"> + <MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/> + </MkPagination> + </MkContainer> + </div> + <MkError v-else-if="error" @retry="fetch()"/> + <MkLoading v-else/> + </transition> </div> </template> @@ -101,10 +97,6 @@ export default defineComponent({ [symbols.PAGE_INFO]: computed(() => this.page ? { title: computed(() => this.page.title || this.page.name), avatar: this.page.user, - } : null), - header: computed(() => this.page ? { - title: computed(() => this.page.title || this.page.name), - avatar: this.page.user, path: `/@${this.page.user.username}/pages/${this.page.name}`, share: { title: this.page.title || this.page.name, diff --git a/src/client/pages/pages.vue b/src/client/pages/pages.vue index 8300e8a6e4..6963682592 100644 --- a/src/client/pages/pages.vue +++ b/src/client/pages/pages.vue @@ -1,37 +1,33 @@ <template> -<div> - <MkHeader :info="header"/> +<MkSpacer> + <!-- TODO: MkHeaderに統合 --> + <MkTab v-model="tab" v-if="$i"> + <option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option> + <option value="my"><i class="fas fa-edit"></i> {{ $ts._pages.my }}</option> + <option value="liked"><i class="fas fa-heart"></i> {{ $ts._pages.liked }}</option> + </MkTab> - <MkSpacer> - <!-- TODO: MkHeaderに統合 --> - <MkTab v-model="tab" v-if="$i"> - <option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option> - <option value="my"><i class="fas fa-edit"></i> {{ $ts._pages.my }}</option> - <option value="liked"><i class="fas fa-heart"></i> {{ $ts._pages.liked }}</option> - </MkTab> - - <div class="_section"> - <div class="rknalgpo _content" v-if="tab === 'featured'"> - <MkPagination :pagination="featuredPagesPagination" #default="{items}"> - <MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/> - </MkPagination> - </div> + <div class="_section"> + <div class="rknalgpo _content" v-if="tab === 'featured'"> + <MkPagination :pagination="featuredPagesPagination" #default="{items}"> + <MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/> + </MkPagination> + </div> - <div class="rknalgpo _content my" v-if="tab === 'my'"> - <MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton> - <MkPagination :pagination="myPagesPagination" #default="{items}"> - <MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/> - </MkPagination> - </div> + <div class="rknalgpo _content my" v-if="tab === 'my'"> + <MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton> + <MkPagination :pagination="myPagesPagination" #default="{items}"> + <MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/> + </MkPagination> + </div> - <div class="rknalgpo _content" v-if="tab === 'liked'"> - <MkPagination :pagination="likedPagesPagination" #default="{items}"> - <MkPagePreview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/> - </MkPagination> - </div> + <div class="rknalgpo _content" v-if="tab === 'liked'"> + <MkPagination :pagination="likedPagesPagination" #default="{items}"> + <MkPagePreview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/> + </MkPagination> </div> - </MkSpacer> -</div> + </div> +</MkSpacer> </template> <script lang="ts"> @@ -52,11 +48,6 @@ export default defineComponent({ title: this.$ts.pages, icon: 'fas fa-sticky-note', bg: 'var(--bg)', - }, - header: { - title: this.$ts.pages, - icon: 'fas fa-sticky-note', - bg: 'var(--bg)', actions: [{ icon: 'fas fa-plus', text: this.$ts.create, diff --git a/src/client/pages/search.vue b/src/client/pages/search.vue index fec138726f..8cf4d32a8f 100644 --- a/src/client/pages/search.vue +++ b/src/client/pages/search.vue @@ -1,10 +1,7 @@ <template> -<div> - <MkHeader :info="header"/> - <div class="_section"> - <div class="_content"> - <XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/> - </div> +<div class="_section"> + <div class="_content"> + <XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/> </div> </div> </template> @@ -26,10 +23,6 @@ export default defineComponent({ title: computed(() => this.$t('searchWith', { q: this.$route.query.q })), icon: 'fas fa-search', }, - header: { - title: computed(() => this.$t('searchWith', { q: this.$route.query.q })), - icon: 'fas fa-search', - }, pagination: { endpoint: 'notes/search', limit: 10, diff --git a/src/client/pages/settings/drive.vue b/src/client/pages/settings/drive.vue index 177bf058f3..2d73eb4df7 100644 --- a/src/client/pages/settings/drive.vue +++ b/src/client/pages/settings/drive.vue @@ -35,7 +35,6 @@ <script lang="ts"> import { defineComponent } from 'vue'; import * as tinycolor from 'tinycolor2'; -import ApexCharts from 'apexcharts'; import FormButton from '@client/components/debobigego/button.vue'; import FormGroup from '@client/components/debobigego/group.vue'; import FormKeyValueView from '@client/components/debobigego/key-value-view.vue'; @@ -44,6 +43,8 @@ import * as os from '@client/os'; import bytes from '@client/filters/bytes'; import * as symbols from '@client/symbols'; +// TODO: render chart + export default defineComponent({ components: { FormBase, @@ -117,104 +118,6 @@ export default defineComponent({ }); }, - renderChart() { - os.api('charts/user/drive', { - userId: this.$i.id, - span: 'day', - limit: 21 - }).then(stats => { - const addition = []; - const deletion = []; - const now = new Date(); - const y = now.getFullYear(); - const m = now.getMonth(); - const d = now.getDate(); - for (let i = 0; i < 21; i++) { - const x = new Date(y, m, d - i); - addition.push([ - x, - stats.incSize[i] - ]); - deletion.push([ - x, - -stats.decSize[i] - ]); - } - const chart = new ApexCharts(this.$refs.chart, { - chart: { - type: 'bar', - stacked: true, - height: 150, - toolbar: { - show: false - }, - zoom: { - enabled: false - } - }, - plotOptions: { - bar: { - columnWidth: '80%' - } - }, - grid: { - clipMarkers: false, - borderColor: 'rgba(0, 0, 0, 0.1)', - xaxis: { - lines: { - show: true, - } - }, - }, - tooltip: { - shared: true, - intersect: false, - theme: this.$store.state.darkMode ? 'dark' : 'light', - }, - dataLabels: { - enabled: false - }, - legend: { - show: false - }, - series: [{ - name: 'Additions', - data: addition - }, { - name: 'Deletions', - data: deletion - }], - xaxis: { - type: 'datetime', - labels: { - style: { - colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--fg')).toRgbString() - } - }, - axisBorder: { - color: 'rgba(0, 0, 0, 0.1)' - }, - axisTicks: { - color: 'rgba(0, 0, 0, 0.1)' - }, - crosshairs: { - width: 1, - opacity: 1 - } - }, - yaxis: { - labels: { - formatter: v => bytes(v, 0), - style: { - colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--fg')).toRgbString() - } - } - } - }); - chart.render(); - }); - }, - bytes } }); diff --git a/src/client/pages/settings/index.vue b/src/client/pages/settings/index.vue index 9da3031a41..cf053dbe63 100644 --- a/src/client/pages/settings/index.vue +++ b/src/client/pages/settings/index.vue @@ -1,9 +1,13 @@ <template> <div class="vvcocwet" :class="{ wide: !narrow }" ref="el"> <div class="nav" v-if="!narrow || page == null"> - <div class="title">{{ $ts.settings }}</div> - <MkInfo v-if="emailNotConfigured" warn class="info">{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></MkInfo> - <MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu> + <MkSpacer :content-max="700"> + <div class="baaadecd"> + <div class="title">{{ $ts.settings }}</div> + <MkInfo v-if="emailNotConfigured" warn class="info">{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></MkInfo> + <MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu> + </div> + </MkSpacer> </div> <div class="main"> <component :is="component" :key="page" v-bind="pageProps"/> @@ -41,6 +45,7 @@ export default defineComponent({ title: i18n.locale.settings, icon: 'fas fa-cog', bg: 'var(--bg)', + hideHeader: true, }; const INFO = ref(indexInfo); const page = ref(props.initialPage); @@ -271,22 +276,24 @@ export default defineComponent({ <style lang="scss" scoped> .vvcocwet { > .nav { - > .title { - margin: 16px; - font-size: 1.5em; - font-weight: bold; - } + .baaadecd { + > .title { + margin: 16px; + font-size: 1.5em; + font-weight: bold; + } - > .info { - margin: 0 16px; - } + > .info { + margin: 0 16px; + } - > .accounts { - > .avatar { - display: block; - width: 50px; - height: 50px; - margin: 8px auto 16px auto; + > .accounts { + > .avatar { + display: block; + width: 50px; + height: 50px; + margin: 8px auto 16px auto; + } } } } @@ -302,8 +309,10 @@ export default defineComponent({ box-sizing: border-box; overflow: auto; - > .title { - margin: 24px; + .baaadecd { + > .title { + margin: 24px 0; + } } } @@ -311,7 +320,6 @@ export default defineComponent({ flex: 1; min-width: 0; overflow: auto; - --baseContentWidth: 100%; } } } diff --git a/src/client/pages/timeline.vue b/src/client/pages/timeline.vue index dfabcbf84b..7b17d585f8 100644 --- a/src/client/pages/timeline.vue +++ b/src/client/pages/timeline.vue @@ -1,21 +1,18 @@ <template> -<div v-hotkey.global="keymap"> - <MkHeader :info="header"/> - <div class="cmuxhskf" v-size="{ min: [800] }"> - <XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/> - <XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/> +<div class="cmuxhskf" v-size="{ min: [800] }" v-hotkey.global="keymap"> + <XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/> + <XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/> - <div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div> - <div class="tl _block"> - <XTimeline ref="tl" class="tl" - :key="src" - :src="src" - :sound="true" - @before="before()" - @after="after()" - @queue="queueUpdated" - /> - </div> + <div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div> + <div class="tl _block"> + <XTimeline ref="tl" class="tl" + :key="src" + :src="src" + :sound="true" + @before="before()" + @after="after()" + @queue="queueUpdated" + /> </div> </div> </template> @@ -46,11 +43,6 @@ export default defineComponent({ title: this.$ts.timeline, icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home', bg: 'var(--bg)', - })), - header: computed(() => ({ - title: this.$ts.timeline, - icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home', - bg: 'var(--bg)', actions: [{ icon: 'fas fa-list-ul', text: this.$ts.lists, @@ -92,7 +84,7 @@ export default defineComponent({ icon: 'fas fa-globe', iconOnly: true, onClick: () => { this.src = 'global'; this.saveSrc(); }, - }] + }], })), }; }, diff --git a/src/client/pages/user/index.activity.vue b/src/client/pages/user/index.activity.vue index 9101c8ae5f..be85c252e8 100644 --- a/src/client/pages/user/index.activity.vue +++ b/src/client/pages/user/index.activity.vue @@ -3,20 +3,21 @@ <template #header><i class="fas fa-chart-bar" style="margin-right: 0.5em;"></i>{{ $ts.activity }}</template> <div style="padding: 8px;"> - <div ref="chart"></div> + <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 ApexCharts from 'apexcharts'; 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: { @@ -29,96 +30,5 @@ export default defineComponent({ default: 40 } }, - data() { - return { - fetching: true, - data: [], - peak: null, - }; - }, - mounted() { - os.api('charts/user/notes', { - userId: this.user.id, - span: 'day', - limit: this.limit - }).then(stats => { - const normal = []; - const reply = []; - const renote = []; - - const now = new Date(); - const y = now.getFullYear(); - const m = now.getMonth(); - const d = now.getDate(); - - for (let i = 0; i < this.limit; i++) { - const x = new Date(y, m, d - i); - normal.push([ - x, - stats.diffs.normal[i] - ]); - reply.push([ - x, - stats.diffs.reply[i] - ]); - renote.push([ - x, - stats.diffs.renote[i] - ]); - } - - const chart = new ApexCharts(this.$refs.chart, { - chart: { - type: 'bar', - stacked: true, - height: 100, - sparkline: { - enabled: true - }, - }, - plotOptions: { - bar: { - columnWidth: '40%' - } - }, - dataLabels: { - enabled: false - }, - grid: { - clipMarkers: false, - padding: { - top: 0, - right: 8, - bottom: 0, - left: 8 - } - }, - tooltip: { - shared: true, - intersect: false, - theme: this.$store.state.darkMode ? 'dark' : 'light', - }, - series: [{ - name: 'Normal', - data: normal - }, { - name: 'Reply', - data: reply - }, { - name: 'Renote', - data: renote - }], - xaxis: { - type: 'datetime', - crosshairs: { - width: 1, - opacity: 1 - } - } - }); - - chart.render(); - }); - } }); </script> diff --git a/src/client/pages/user/index.timeline.vue b/src/client/pages/user/index.timeline.vue index 9057d90396..c3444f26f6 100644 --- a/src/client/pages/user/index.timeline.vue +++ b/src/client/pages/user/index.timeline.vue @@ -65,11 +65,4 @@ export default defineComponent({ background: var(--bg); } } - -._fitSide_ .yrzkoczt { - > .tab { - padding-left: var(--margin); - padding-right: var(--margin); - } -} </style> diff --git a/src/client/pages/user/index.vue b/src/client/pages/user/index.vue index f74bf49883..5074c4531c 100644 --- a/src/client/pages/user/index.vue +++ b/src/client/pages/user/index.vue @@ -1,87 +1,86 @@ <template> -<div> - <MkHeader :info="header"/> - <transition name="fade" mode="out-in"> - <div class="ftskorzw wide" v-if="user && narrow === false"> - <MkRemoteCaution v-if="user.host != null" :href="user.url"/> +<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 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="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 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> - <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"/> + <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> - <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 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 class="ftskorzw narrow _root" v-else-if="user && narrow === true" v-size="{ max: [500] }"> + </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> --> @@ -173,7 +172,7 @@ </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"/> + <XActivity :user="user" :key="user.id" style="margin-top: var(--margin);"/> </div> <div> <XUserTimeline :user="user"/> @@ -187,10 +186,10 @@ <XGallery v-else-if="page === 'gallery'" :user="user" class="_gap"/> </div> </div> - <MkError v-else-if="error" @retry="fetch()"/> - <MkLoading v-else/> - </transition> -</div> + </MkSpacer> + <MkError v-else-if="error" @retry="fetch()"/> + <MkLoading v-else/> +</transition> </template> <script lang="ts"> @@ -249,14 +248,6 @@ export default defineComponent({ [symbols.PAGE_INFO]: computed(() => this.user ? { icon: 'fas fa-user', title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`, - path: `/@${this.user.username}`, - share: { - title: this.user.name, - }, - bg: 'var(--bg)', - } : null), - header: computed(() => this.user ? { - title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`, subtitle: `@${getAcct(this.user)}`, userName: this.user, avatar: this.user, @@ -290,7 +281,7 @@ export default defineComponent({ title: this.$ts.gallery, icon: 'fas fa-icons', onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/gallery'); }, - }] + }], } : null), user: null, error: null, @@ -833,16 +824,4 @@ export default defineComponent({ } } } - -._fitSide_ .ftskorzw.narrow { - > .profile { - > .warn { - margin: 0; - } - - > .main { - margin-top: 0; - } - } -} </style> diff --git a/src/client/store.ts b/src/client/store.ts index e4b762873d..eea3955fac 100644 --- a/src/client/store.ts +++ b/src/client/store.ts @@ -144,7 +144,7 @@ export const defaultStore = markRaw(new Storage('base', { }, useBlurEffect: { where: 'device', - default: false + default: true }, showFixedPostForm: { where: 'device', diff --git a/src/client/style.scss b/src/client/style.scss index d6bad5a24d..d77cdacf7b 100644 --- a/src/client/style.scss +++ b/src/client/style.scss @@ -1,7 +1,6 @@ @charset "utf-8"; :root { - --baseContentWidth: 760px; --radius: 12px; --marginFull: 16px; --marginHalf: 10px; @@ -350,21 +349,6 @@ hr { } // TODO: 廃止 -._root { - box-sizing: border-box; - margin: var(--root-margin, 32px) auto; - max-width: min(var(--baseContentWidth), calc(100% - (var(--root-margin, 32px) * 2))); - - // 子marginが突き抜けるのを防ぐため - // https://stackoverflow.com/questions/1762539/margin-on-child-element-moves-parent-element - padding-top: 1px; - margin-top: calc(var(--root-margin, 32px) - 1px); - - @media (max-width: 500px) { - --root-margin: 10px; - } -} - ._monolithic_ { ._section:not(:empty) { box-sizing: border-box; @@ -380,33 +364,6 @@ hr { } } -._fitSide_ { - --root-margin: 0px; - --baseContentWidth: 100%; - --panelBorder: none; - - ._block { - //border-top: solid 0.5px var(--divider); - //border-bottom: solid 0.5px var(--divider); - border-radius: 0; - box-shadow: none; - } - - ._isolated { - margin: var(--margin); - } - - ._block._isolated { - border-radius: var(--radius); - } - - @media (max-width: 500px) { - ._root { - --root-margin: 0px; - } - } -} - ._narrow_ ._card { > ._title { padding: 16px; diff --git a/src/client/ui/_common_/sidebar.vue b/src/client/ui/_common_/sidebar.vue index ec2a17ab86..ece80e60d9 100644 --- a/src/client/ui/_common_/sidebar.vue +++ b/src/client/ui/_common_/sidebar.vue @@ -26,7 +26,7 @@ </template> <div class="divider"></div> <MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" v-click-anime> - <i class="fas fa-server fa-fw"></i><span class="text">{{ $ts.instance }}</span> + <i class="fas fa-door-open fa-fw"></i><span class="text">{{ $ts.controlPanel }}</span> </MkA> <button class="item _button" @click="more" v-click-anime> <i class="fa fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span> diff --git a/src/client/ui/chat/side.vue b/src/client/ui/chat/side.vue index 3fd0a0e77b..a8a538c75b 100644 --- a/src/client/ui/chat/side.vue +++ b/src/client/ui/chat/side.vue @@ -3,7 +3,7 @@ <header class="header" @contextmenu.prevent.stop="onContextmenu"> <MkHeader class="title" :info="pageInfo" :center="false"/> </header> - <component :is="component" v-bind="props" :ref="changePage" class="body _fitSide_"/> + <component :is="component" v-bind="props" :ref="changePage" class="body"/> </div> </template> diff --git a/src/client/ui/default.header.vue b/src/client/ui/classic.header.vue index 908a4719a4..ad5080e3f6 100644 --- a/src/client/ui/default.header.vue +++ b/src/client/ui/classic.header.vue @@ -13,8 +13,8 @@ </component> </template> <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime v-tooltip="$ts.instance"> - <i class="fas fa-server fa-fw"></i> + <MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime v-tooltip="$ts.controlPanel"> + <i class="fas fa-door-open fa-fw"></i> </MkA> <button class="item _button" @click="more" v-click-anime> <i class="fas fa-ellipsis-h fa-fw"></i> diff --git a/src/client/ui/default.side.vue b/src/client/ui/classic.side.vue index c7d2abff26..c7d2abff26 100644 --- a/src/client/ui/default.side.vue +++ b/src/client/ui/classic.side.vue diff --git a/src/client/ui/default.sidebar.vue b/src/client/ui/classic.sidebar.vue index cce74a53cd..ac061d446b 100644 --- a/src/client/ui/default.sidebar.vue +++ b/src/client/ui/classic.sidebar.vue @@ -21,7 +21,7 @@ </template> <div class="divider"></div> <MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime> - <i class="fas fa-server fa-fw"></i><span class="text">{{ $ts.instance }}</span> + <i class="fas fa-door-open fa-fw"></i><span class="text">{{ $ts.controlPanel }}</span> </MkA> <button class="item _button" @click="more" v-click-anime> <i class="fas fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span> diff --git a/src/client/ui/default.vue b/src/client/ui/classic.vue index 3518b1a91a..79cdbe3af1 100644 --- a/src/client/ui/default.vue +++ b/src/client/ui/classic.vue @@ -13,14 +13,17 @@ </template> <main class="main" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }"> - <div class="content" :class="{ _fitSide_: !fullView }"> - <router-view v-slot="{ Component }"> - <transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> - <keep-alive :include="['timeline']"> - <component :is="Component" :ref="changePage"/> - </keep-alive> - </transition> - </router-view> + <div class="content"> + <MkStickyContainer> + <template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template> + <router-view v-slot="{ Component }"> + <transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> + <keep-alive :include="['timeline']"> + <component :is="Component" :ref="changePage"/> + </keep-alive> + </transition> + </router-view> + </MkStickyContainer> </div> </main> @@ -61,7 +64,7 @@ import { defineComponent, defineAsyncComponent, markRaw } from 'vue'; import { instanceName } from '@client/config'; import { StickySidebar } from '@client/scripts/sticky-sidebar'; -import XSidebar from './default.sidebar.vue'; +import XSidebar from './classic.sidebar.vue'; import XDrawerSidebar from '@client/ui/_common_/sidebar.vue'; import XCommon from './_common_/common.vue'; import * as os from '@client/os'; @@ -76,8 +79,8 @@ export default defineComponent({ XCommon, XSidebar, XDrawerSidebar, - XHeaderMenu: defineAsyncComponent(() => import('./default.header.vue')), - XWidgets: defineAsyncComponent(() => import('./default.widgets.vue')), + XHeaderMenu: defineAsyncComponent(() => import('./classic.header.vue')), + XWidgets: defineAsyncComponent(() => import('./classic.widgets.vue')), }, provide() { diff --git a/src/client/ui/default.widgets.vue b/src/client/ui/classic.widgets.vue index f9584402a2..f9584402a2 100644 --- a/src/client/ui/default.widgets.vue +++ b/src/client/ui/classic.widgets.vue diff --git a/src/client/ui/deck/main-column.vue b/src/client/ui/deck/main-column.vue index baf88a9721..8e36caa3ce 100644 --- a/src/client/ui/deck/main-column.vue +++ b/src/client/ui/deck/main-column.vue @@ -7,13 +7,16 @@ </template> </template> - <router-view v-slot="{ Component }" class="_fitSide_"> - <transition> - <keep-alive :include="['timeline']"> - <component :is="Component" :ref="changePage" @contextmenu.stop="onContextmenu"/> - </keep-alive> - </transition> - </router-view> + <MkStickyContainer> + <template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template> + <router-view v-slot="{ Component }"> + <transition> + <keep-alive :include="['timeline']"> + <component :is="Component" :ref="changePage" @contextmenu.stop="onContextmenu"/> + </keep-alive> + </transition> + </router-view> + </MkStickyContainer> </XColumn> </template> diff --git a/src/client/ui/universal.vue b/src/client/ui/universal.vue index 7c25d71bb3..d8f1c2a934 100644 --- a/src/client/ui/universal.vue +++ b/src/client/ui/universal.vue @@ -5,13 +5,16 @@ <div class="contents" ref="contents" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }"> <main ref="main"> <div class="content"> - <router-view v-slot="{ Component }"> - <transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> - <keep-alive :include="['timeline']"> - <component :is="Component" :ref="changePage"/> - </keep-alive> - </transition> - </router-view> + <MkStickyContainer> + <template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template> + <router-view v-slot="{ Component }"> + <transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> + <keep-alive :include="['timeline']"> + <component :is="Component" :ref="changePage"/> + </keep-alive> + </transition> + </router-view> + </MkStickyContainer> </div> <div class="spacer"></div> </main> @@ -55,7 +58,7 @@ import { instanceName } from '@client/config'; import { StickySidebar } from '@client/scripts/sticky-sidebar'; import XSidebar from '@client/ui/_common_/sidebar.vue'; import XCommon from './_common_/common.vue'; -import XSide from './default.side.vue'; +import XSide from './classic.side.vue'; import * as os from '@client/os'; import { menuDef } from '@client/menu'; import * as symbols from '@client/symbols'; diff --git a/src/client/widgets/notifications.vue b/src/client/widgets/notifications.vue index b0245eed6a..5e2648f5b9 100644 --- a/src/client/widgets/notifications.vue +++ b/src/client/widgets/notifications.vue @@ -3,7 +3,7 @@ <template #header><i class="fas fa-bell"></i>{{ $ts.notifications }}</template> <template #func><button @click="configure()" class="_button"><i class="fas fa-cog"></i></button></template> - <div class="_fitSide_"> + <div> <XNotifications :include-types="props.includingTypes"/> </div> </MkContainer> |