mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-27 23:20:21 +01:00
Add featured page
This commit is contained in:
parent
8e3d884081
commit
95b157ac3e
8 changed files with 182 additions and 9 deletions
|
@ -29,6 +29,7 @@ common:
|
||||||
enter-password: "パスワードを入力してください"
|
enter-password: "パスワードを入力してください"
|
||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
customize-home: "ホームをカスタマイズ"
|
customize-home: "ホームをカスタマイズ"
|
||||||
|
featured-notes: "ハイライト"
|
||||||
|
|
||||||
got-it: "わかった"
|
got-it: "わかった"
|
||||||
customization-tips:
|
customization-tips:
|
||||||
|
|
|
@ -134,6 +134,7 @@ init(async (launch, os) => {
|
||||||
{ path: '/@:user', name: 'user', component: () => import('./views/deck/deck.user-column.vue').then(m => m.default) },
|
{ path: '/@:user', name: 'user', component: () => import('./views/deck/deck.user-column.vue').then(m => m.default) },
|
||||||
{ path: '/notes/:note', name: 'note', component: () => import('./views/deck/deck.note-column.vue').then(m => m.default) },
|
{ path: '/notes/:note', name: 'note', component: () => import('./views/deck/deck.note-column.vue').then(m => m.default) },
|
||||||
{ path: '/tags/:tag', name: 'tag', component: () => import('./views/deck/deck.hashtag-column.vue').then(m => m.default) },
|
{ path: '/tags/:tag', name: 'tag', component: () => import('./views/deck/deck.hashtag-column.vue').then(m => m.default) },
|
||||||
|
{ path: '/featured', component: () => import('./views/deck/deck.featured-column.vue').then(m => m.default) },
|
||||||
{ path: '/i/favorites', component: () => import('./views/deck/deck.favorites-column.vue').then(m => m.default) }
|
{ path: '/i/favorites', component: () => import('./views/deck/deck.favorites-column.vue').then(m => m.default) }
|
||||||
]}
|
]}
|
||||||
: { path: '/', component: MkHome, children: [
|
: { path: '/', component: MkHome, children: [
|
||||||
|
@ -141,6 +142,7 @@ init(async (launch, os) => {
|
||||||
{ path: '/@:user', name: 'user', component: () => import('./views/home/user/user.vue').then(m => m.default) },
|
{ path: '/@:user', name: 'user', component: () => import('./views/home/user/user.vue').then(m => m.default) },
|
||||||
{ path: '/notes/:note', name: 'note', component: () => import('./views/home/note.vue').then(m => m.default) },
|
{ path: '/notes/:note', name: 'note', component: () => import('./views/home/note.vue').then(m => m.default) },
|
||||||
{ path: '/tags/:tag', name: 'tag', component: () => import('./views/home/tag.vue').then(m => m.default) },
|
{ path: '/tags/:tag', name: 'tag', component: () => import('./views/home/tag.vue').then(m => m.default) },
|
||||||
|
{ path: '/featured', component: () => import('./views/home/featured.vue').then(m => m.default) },
|
||||||
{ path: '/i/favorites', component: () => import('./views/home/favorites.vue').then(m => m.default) }
|
{ path: '/i/favorites', component: () => import('./views/home/favorites.vue').then(m => m.default) }
|
||||||
]},
|
]},
|
||||||
{ path: '/i/messaging/:user', component: MkMessagingRoom },
|
{ path: '/i/messaging/:user', component: MkMessagingRoom },
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
<template v-if="hasUnreadMessagingMessage"><fa icon="circle"/></template>
|
<template v-if="hasUnreadMessagingMessage"><fa icon="circle"/></template>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
</template>
|
||||||
|
<li class="featured">
|
||||||
|
<router-link to="/featured"><fa :icon="faNewspaper"/><p>{{ $t('@.featured-notes') }}</p></router-link>
|
||||||
|
</li>
|
||||||
<li class="game">
|
<li class="game">
|
||||||
<a @click="game">
|
<a @click="game">
|
||||||
<fa icon="gamepad"/>
|
<fa icon="gamepad"/>
|
||||||
|
@ -32,7 +36,6 @@
|
||||||
<template v-if="hasGameInvitations"><fa icon="circle"/></template>
|
<template v-if="hasGameInvitations"><fa icon="circle"/></template>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -42,13 +45,15 @@ import Vue from 'vue';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
import MkMessagingWindow from './messaging-window.vue';
|
import MkMessagingWindow from './messaging-window.vue';
|
||||||
import MkGameWindow from './game-window.vue';
|
import MkGameWindow from './game-window.vue';
|
||||||
|
import { faNewspaper } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('desktop/views/components/ui.header.nav.vue'),
|
i18n: i18n('desktop/views/components/ui.header.nav.vue'),
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasGameInvitations: false,
|
hasGameInvitations: false,
|
||||||
connection: null
|
connection: null,
|
||||||
|
faNewspaper
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
59
src/client/app/desktop/views/deck/deck.featured-column.vue
Normal file
59
src/client/app/desktop/views/deck/deck.featured-column.vue
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<template>
|
||||||
|
<x-column>
|
||||||
|
<span slot="header">
|
||||||
|
<fa :icon="faNewspaper"/>{{ $t('@.featured-notes') }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<x-notes ref="timeline" :more="null"/>
|
||||||
|
</div>
|
||||||
|
</x-column>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import i18n from '../../../i18n';
|
||||||
|
import XColumn from './deck.column.vue';
|
||||||
|
import XNotes from './deck.notes.vue';
|
||||||
|
import { faNewspaper } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
i18n: i18n(),
|
||||||
|
|
||||||
|
components: {
|
||||||
|
XColumn,
|
||||||
|
XNotes,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fetching: true,
|
||||||
|
faNewspaper
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
fetch() {
|
||||||
|
this.fetching = true;
|
||||||
|
|
||||||
|
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
||||||
|
this.$root.api('notes/featured', {
|
||||||
|
limit: 15,
|
||||||
|
}).then(notes => {
|
||||||
|
res(notes);
|
||||||
|
this.fetching = false;
|
||||||
|
this.$emit('loaded');
|
||||||
|
}, rej);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.$refs.timeline.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
54
src/client/app/desktop/views/home/featured.vue
Normal file
54
src/client/app/desktop/views/home/featured.vue
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<template>
|
||||||
|
<div class="glowckho" v-if="!fetching">
|
||||||
|
<sequential-entrance animation="entranceFromTop" delay="25">
|
||||||
|
<template v-for="note in notes">
|
||||||
|
<mk-note-detail class="post" :note="note" :key="note.id"/>
|
||||||
|
</template>
|
||||||
|
</sequential-entrance>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Progress from '../../../common/scripts/loading';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fetching: true,
|
||||||
|
notes: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetch() {
|
||||||
|
Progress.start();
|
||||||
|
this.fetching = true;
|
||||||
|
|
||||||
|
this.$root.api('notes/featured', {
|
||||||
|
limit: 10
|
||||||
|
}).then(notes => {
|
||||||
|
this.notes = notes;
|
||||||
|
this.fetching = false;
|
||||||
|
|
||||||
|
Progress.done();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.glowckho
|
||||||
|
margin 0 auto
|
||||||
|
|
||||||
|
> * > .post
|
||||||
|
margin-bottom 16px
|
||||||
|
|
||||||
|
> .more
|
||||||
|
margin 32px 16px 16px 16px
|
||||||
|
text-align center
|
||||||
|
|
||||||
|
</style>
|
|
@ -12,7 +12,6 @@ import init from '../init';
|
||||||
|
|
||||||
import MkIndex from './views/pages/index.vue';
|
import MkIndex from './views/pages/index.vue';
|
||||||
import MkSignup from './views/pages/signup.vue';
|
import MkSignup from './views/pages/signup.vue';
|
||||||
import MkUser from './views/pages/user.vue';
|
|
||||||
import MkSelectDrive from './views/pages/selectdrive.vue';
|
import MkSelectDrive from './views/pages/selectdrive.vue';
|
||||||
import MkDrive from './views/pages/drive.vue';
|
import MkDrive from './views/pages/drive.vue';
|
||||||
import MkNotifications from './views/pages/notifications.vue';
|
import MkNotifications from './views/pages/notifications.vue';
|
||||||
|
@ -134,6 +133,7 @@ init((launch) => {
|
||||||
{ path: '/selectdrive', component: MkSelectDrive },
|
{ path: '/selectdrive', component: MkSelectDrive },
|
||||||
{ path: '/search', component: MkSearch },
|
{ path: '/search', component: MkSearch },
|
||||||
{ path: '/tags/:tag', component: MkTag },
|
{ path: '/tags/:tag', component: MkTag },
|
||||||
|
{ path: '/featured', name: 'featured', component: () => import('./views/pages/featured.vue').then(m => m.default) },
|
||||||
{ path: '/share', component: MkShare },
|
{ path: '/share', component: MkShare },
|
||||||
{ path: '/games/reversi/:game?', name: 'reversi', component: MkReversi },
|
{ path: '/games/reversi/:game?', name: 'reversi', component: MkReversi },
|
||||||
{ path: '/@:user', component: () => import('./views/pages/user.vue').then(m => m.default) },
|
{ path: '/@:user', component: () => import('./views/pages/user.vue').then(m => m.default) },
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'"><i><fa :icon="['far', 'bell']" fixed-width/></i>{{ $t('notifications') }}<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
|
<li><router-link to="/i/notifications" :data-active="$route.name == 'notifications'"><i><fa :icon="['far', 'bell']" fixed-width/></i>{{ $t('notifications') }}<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
|
||||||
<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'"><i><fa :icon="['far', 'comments']" fixed-width/></i>{{ $t('@.messaging') }}<i v-if="hasUnreadMessagingMessage" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
|
<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'"><i><fa :icon="['far', 'comments']" fixed-width/></i>{{ $t('@.messaging') }}<i v-if="hasUnreadMessagingMessage" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
|
||||||
<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'"><i><fa :icon="['far', 'envelope']" fixed-width/></i>{{ $t('follow-requests') }}<i v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
|
<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'"><i><fa :icon="['far', 'envelope']" fixed-width/></i>{{ $t('follow-requests') }}<i v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
|
||||||
|
<li><router-link to="/featured" :data-active="$route.name == 'featured'"><i><fa :icon="faNewspaper" fixed-width/></i>{{ $t('@.featured-notes') }}<i><fa icon="angle-right"/></i></router-link></li>
|
||||||
<li><router-link to="/games/reversi" :data-active="$route.name == 'reversi'"><i><fa icon="gamepad" fixed-width/></i>{{ $t('game') }}<i v-if="hasGameInvitation" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
|
<li><router-link to="/games/reversi" :data-active="$route.name == 'reversi'"><i><fa icon="gamepad" fixed-width/></i>{{ $t('game') }}<i v-if="hasGameInvitation" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -50,6 +51,7 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import i18n from '../../../i18n';
|
import i18n from '../../../i18n';
|
||||||
import { lang } from '../../../config';
|
import { lang } from '../../../config';
|
||||||
|
import { faNewspaper } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
i18n: i18n('mobile/views/components/ui.nav.vue'),
|
i18n: i18n('mobile/views/components/ui.nav.vue'),
|
||||||
|
@ -62,6 +64,7 @@ export default Vue.extend({
|
||||||
aboutUrl: `/docs/${lang}/about`,
|
aboutUrl: `/docs/${lang}/about`,
|
||||||
announcements: [],
|
announcements: [],
|
||||||
searching: false,
|
searching: false,
|
||||||
|
faNewspaper
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
49
src/client/app/mobile/views/pages/featured.vue
Normal file
49
src/client/app/mobile/views/pages/featured.vue
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<mk-ui>
|
||||||
|
<span slot="header"><span style="margin-right:4px;"><fa :icon="faNewspaper"/></span>{{ $t('@.featured-notes') }}</span>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<sequential-entrance animation="entranceFromTop" delay="25">
|
||||||
|
<template v-for="note in notes">
|
||||||
|
<mk-note-detail class="post" :note="note" :key="note.id"/>
|
||||||
|
</template>
|
||||||
|
</sequential-entrance>
|
||||||
|
</main>
|
||||||
|
</mk-ui>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import i18n from '../../../i18n';
|
||||||
|
import Progress from '../../../common/scripts/loading';
|
||||||
|
import { faNewspaper } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
i18n: i18n(''),
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fetching: true,
|
||||||
|
notes: [],
|
||||||
|
faNewspaper
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetch() {
|
||||||
|
Progress.start();
|
||||||
|
this.fetching = true;
|
||||||
|
|
||||||
|
this.$root.api('notes/featured', {
|
||||||
|
limit: 10
|
||||||
|
}).then(notes => {
|
||||||
|
this.notes = notes;
|
||||||
|
this.fetching = false;
|
||||||
|
|
||||||
|
Progress.done();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Reference in a new issue