summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-10-25 02:34:58 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-10-25 02:34:58 +0900
commit6d557269c13f023d80aeeb28ddceb7337aca134c (patch)
treef69595ca45dd0d05dc3af4404dd8205dc828ddc1 /src
parentMerge branch 'develop' (diff)
parent12.94.0 (diff)
downloadmisskey-6d557269c13f023d80aeeb28ddceb7337aca134c.tar.gz
misskey-6d557269c13f023d80aeeb28ddceb7337aca134c.tar.bz2
misskey-6d557269c13f023d80aeeb28ddceb7337aca134c.zip
Merge branch 'develop'
Diffstat (limited to 'src')
-rw-r--r--src/client/components/chart.vue41
-rw-r--r--src/client/components/global/header.vue9
-rw-r--r--src/client/components/global/sticky-container.vue74
-rw-r--r--src/client/components/index.ts2
-rw-r--r--src/client/components/media-image.vue12
-rw-r--r--src/client/components/media-list.vue97
-rw-r--r--src/client/components/mention.vue8
-rw-r--r--src/client/components/modal-page-window.vue11
-rw-r--r--src/client/components/page-window.vue7
-rw-r--r--src/client/components/queue-chart.vue22
-rw-r--r--src/client/components/reactions-viewer.details.vue54
-rw-r--r--src/client/components/reactions-viewer.reaction.vue1
-rw-r--r--src/client/components/ui/folder.vue6
-rw-r--r--src/client/components/ui/info.vue4
-rw-r--r--src/client/components/ui/super-menu.vue5
-rw-r--r--src/client/components/ui/tooltip.vue12
-rw-r--r--src/client/init.ts4
-rw-r--r--src/client/menu.ts14
-rw-r--r--src/client/pages/admin/ads.vue82
-rw-r--r--src/client/pages/admin/announcements.vue45
-rw-r--r--src/client/pages/admin/emojis.vue9
-rw-r--r--src/client/pages/admin/index.vue61
-rw-r--r--src/client/pages/admin/overview.vue122
-rw-r--r--src/client/pages/admin/users.vue9
-rw-r--r--src/client/pages/announcements.vue40
-rw-r--r--src/client/pages/emojis.vue12
-rw-r--r--src/client/pages/explore.vue11
-rw-r--r--src/client/pages/favorites.vue14
-rw-r--r--src/client/pages/featured.vue14
-rw-r--r--src/client/pages/federation.vue182
-rw-r--r--src/client/pages/mentions.vue14
-rw-r--r--src/client/pages/messages.vue14
-rw-r--r--src/client/pages/messaging/index.vue15
-rw-r--r--src/client/pages/my-lists/index.vue26
-rw-r--r--src/client/pages/my-lists/list.vue55
-rw-r--r--src/client/pages/note.vue78
-rw-r--r--src/client/pages/notifications.vue24
-rw-r--r--src/client/pages/page-editor/page-editor.vue134
-rw-r--r--src/client/pages/page.vue108
-rw-r--r--src/client/pages/pages.vue59
-rw-r--r--src/client/pages/search.vue13
-rw-r--r--src/client/pages/settings/drive.vue101
-rw-r--r--src/client/pages/settings/index.vue48
-rw-r--r--src/client/pages/timeline.vue36
-rw-r--r--src/client/pages/user/index.activity.vue96
-rw-r--r--src/client/pages/user/index.timeline.vue7
-rw-r--r--src/client/pages/user/index.vue185
-rw-r--r--src/client/store.ts2
-rw-r--r--src/client/style.scss43
-rw-r--r--src/client/ui/_common_/sidebar.vue2
-rw-r--r--src/client/ui/chat/side.vue2
-rw-r--r--src/client/ui/classic.header.vue (renamed from src/client/ui/default.header.vue)4
-rw-r--r--src/client/ui/classic.side.vue (renamed from src/client/ui/default.side.vue)0
-rw-r--r--src/client/ui/classic.sidebar.vue (renamed from src/client/ui/default.sidebar.vue)2
-rw-r--r--src/client/ui/classic.vue (renamed from src/client/ui/default.vue)25
-rw-r--r--src/client/ui/classic.widgets.vue (renamed from src/client/ui/default.widgets.vue)0
-rw-r--r--src/client/ui/deck/main-column.vue17
-rw-r--r--src/client/ui/universal.vue19
-rw-r--r--src/client/widgets/notifications.vue2
-rw-r--r--src/docs/zh-CN/advanced/stream.md22
-rw-r--r--src/misc/twemoji-base.ts2
-rw-r--r--src/models/repositories/user.ts10
-rw-r--r--src/server/index.ts18
-rw-r--r--src/server/web/index.ts16
64 files changed, 986 insertions, 1197 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>
diff --git a/src/docs/zh-CN/advanced/stream.md b/src/docs/zh-CN/advanced/stream.md
index 3351f2d839..16093e0b96 100644
--- a/src/docs/zh-CN/advanced/stream.md
+++ b/src/docs/zh-CN/advanced/stream.md
@@ -34,8 +34,8 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
ひとつのストリーム上で、同時に複数のチャンネルに接続することができます。
-### チャンネルに接続する
-チャンネルに接続するには、次のようなデータをJSONでストリームに送信します:
+### 连接到频道
+要连接到频道,请将JSON数据发送到流:
```json
{
@@ -51,16 +51,16 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
```
其中:
-* `channel`には接続したいチャンネル名を設定します。チャンネルの種類については後述します。
+* `channel`には接続したいチャンネル名を設定します。频道类型将在后面说明。
* `id`にはそのチャンネルとやり取りするための任意のIDを設定します。ストリームでは様々なメッセージが流れるので、そのメッセージがどのチャンネルからのものなのか識別する必要があるからです。このIDは、UUIDや、乱数のようなもので構いません。
* `params`はチャンネルに接続する際のパラメータです。チャンネルによって接続時に必要とされるパラメータは異なります。パラメータ不要のチャンネルに接続する際は、このプロパティは省略可能です。
<div class="info">ℹ️ IDはチャンネルごとではなく「チャンネルの接続ごと」です。なぜなら、同じチャンネルに異なるパラメータで複数接続するケースもあるからです。</div>
-### チャンネルからのメッセージを受け取る
+### 从频道接收消息
例えばタイムラインのチャンネルなら、新しい投稿があった時にメッセージを発します。そのメッセージを受け取ることで、タイムラインに新しい投稿がされたことをリアルタイムで知ることができます。
-チャンネルがメッセージを発すると、次のようなデータがJSONでストリームに流れてきます:
+当频道发送消息时,以下数据将以JSON格式传输到流中:
```json
{
type: 'channel',
@@ -79,10 +79,10 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
* `type`にはメッセージの種類が設定されます。チャンネルによって、どのような種類のメッセージが流れてくるかは異なります。
* `body`にはメッセージの内容が設定されます。チャンネルによって、どのような内容のメッセージが流れてくるかは異なります。
-### チャンネルに向けてメッセージを送信する
+### 向频道发送消息
チャンネルによっては、メッセージを受け取るだけでなく、こちらから何かメッセージを送信し、何らかの操作を行える場合があります。
-チャンネルにメッセージを送信するには、次のようなデータをJSONでストリームに送信します:
+要将消息发送到频道,请将JSON格式数据发送到流:
```json
{
type: 'channel',
@@ -101,7 +101,7 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
* `type`にはメッセージの種類を設定します。チャンネルによって、どのような種類のメッセージを受け付けるかは異なります。
* `body`にはメッセージの内容を設定します。チャンネルによって、どのような内容のメッセージを受け付けるかは異なります。
-### チャンネルから切断する
+### 断开频道连接
チャンネルから切断するには、次のようなデータをJSONでストリームに送信します:
```json
@@ -116,7 +116,7 @@ MisskeyのストリーミングAPIにはチャンネルという概念があり
其中:
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。
-## ストリームを経由してAPIリクエストする
+## 通过流发送API请求
ストリームを経由してAPIリクエストすると、HTTPリクエストを発生させずにAPIを利用できます。そのため、コードを簡潔にできたり、パフォーマンスの向上を見込めるかもしれません。
@@ -207,7 +207,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
* `body`内の`type`に、イベントの種類が設定されます。
* `body`内の`body`に、イベントの詳細が設定されます。
-#### イベントの種類
+#### 事件类型
##### `reacted`
その投稿にリアクションがされた時に発生します。
@@ -233,7 +233,7 @@ Misskeyは投稿のキャプチャと呼ばれる仕組みを提供していま
##### `deleted`
その投稿が削除された時に発生します。
-* `deletedAt`に、削除日時が設定されます。
+* `deletedAt`表示删除的日期和时间。
例:
```json
diff --git a/src/misc/twemoji-base.ts b/src/misc/twemoji-base.ts
index e08556bd49..cd50311b15 100644
--- a/src/misc/twemoji-base.ts
+++ b/src/misc/twemoji-base.ts
@@ -1 +1 @@
-export const twemojiSvgBase = 'https://twemoji.maxcdn.com/v/latest/svg';
+export const twemojiSvgBase = '/twemoji';
diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts
index 2b77b613a8..72cefbaac5 100644
--- a/src/models/repositories/user.ts
+++ b/src/models/repositories/user.ts
@@ -155,6 +155,14 @@ export class UserRepository extends Repository<User> {
);
}
+ public getAvatarUrl(user: User): string {
+ if (user.avatarUrl) {
+ return user.avatarUrl;
+ } else {
+ return `${config.url}/random-avatar/${user.id}`;
+ }
+ }
+
public async pack(
src: User['id'] | User,
me?: { id: User['id'] } | null | undefined,
@@ -186,7 +194,7 @@ export class UserRepository extends Repository<User> {
name: user.name,
username: user.username,
host: user.host,
- avatarUrl: user.avatarUrl ? user.avatarUrl : config.url + '/avatar/' + user.id,
+ avatarUrl: this.getAvatarUrl(user),
avatarBlurhash: user.avatarBlurhash,
avatarColor: null, // 後方互換性のため
isAdmin: user.isAdmin || falsy,
diff --git a/src/server/index.ts b/src/server/index.ts
index c891596140..5e1a12e4d3 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -26,6 +26,7 @@ import { networkChart } from '@/services/chart/index';
import { genAvatar } from '@/misc/gen-avatar';
import { createTemp } from '@/misc/create-temp';
import { publishMainStream } from '@/services/stream';
+import { parseAcct } from '@/misc/acct';
export const serverLogger = new Logger('server', 'gray', false);
@@ -68,7 +69,22 @@ router.use(activityPub.routes());
router.use(nodeinfo.routes());
router.use(wellKnown.routes());
-router.get('/avatar/:x', async ctx => {
+router.get('/avatar/@:acct', async ctx => {
+ const { username, host } = parseAcct(ctx.params.acct);
+ const user = await Users.findOne({
+ usernameLower: username.toLowerCase(),
+ host: host === config.host ? null : host,
+ isSuspended: false
+ });
+
+ if (user) {
+ ctx.redirect(Users.getAvatarUrl(user));
+ } else {
+ ctx.redirect('/static-assets/user-unknown.png');
+ }
+});
+
+router.get('/random-avatar/:x', async ctx => {
const [temp] = await createTemp();
await genAvatar(ctx.params.x, fs.createWriteStream(temp));
ctx.set('Content-Type', 'image/png');
diff --git a/src/server/web/index.ts b/src/server/web/index.ts
index 8f9b6add6e..35337868d9 100644
--- a/src/server/web/index.ts
+++ b/src/server/web/index.ts
@@ -101,6 +101,22 @@ router.get('/apple-touch-icon.png', async ctx => {
});
});
+router.get('/twemoji/(.*)', async ctx => {
+ const path = ctx.path.replace('/twemoji/', '');
+
+ if (!path.match(/^[0-9a-f-]+\.svg$/)) {
+ ctx.status = 404;
+ return;
+ }
+
+ ctx.set('Content-Security-Policy', `default-src 'none'; style-src 'unsafe-inline'`);
+
+ await send(ctx as any, path, {
+ root: `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/`,
+ maxage: ms('30 days'),
+ });
+});
+
// ServiceWorker
router.get('/sw.js', async ctx => {
await send(ctx as any, `/sw.${config.version}.js`, {