diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2019-02-15 05:08:59 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-02-15 05:08:59 +0900 |
| commit | 53422ffcb296be404c0f3ef7e175bedecca4fb4d (patch) | |
| tree | 39cb47b43edd8b8265bb9ad48becdea2666f8881 /src | |
| parent | Update README.md [AUTOGEN] (#4253) (diff) | |
| download | sharkey-53422ffcb296be404c0f3ef7e175bedecca4fb4d.tar.gz sharkey-53422ffcb296be404c0f3ef7e175bedecca4fb4d.tar.bz2 sharkey-53422ffcb296be404c0f3ef7e175bedecca4fb4d.zip | |
Improve desktop UX (#4262)
* wip
* wip
* wip
* wip
* wip
* wip
* Merge
* wip
* wip
* wip
* wip
* wip
* wip
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/app/common/views/components/activity.vue (renamed from src/client/app/mobile/views/components/activity.vue) | 25 | ||||
| -rw-r--r-- | src/client/app/common/views/components/dummy.vue | 11 | ||||
| -rw-r--r-- | src/client/app/common/views/components/follow-button.vue | 11 | ||||
| -rw-r--r-- | src/client/app/common/views/components/index.ts | 2 | ||||
| -rw-r--r-- | src/client/app/common/views/widgets/index.ts | 2 | ||||
| -rw-r--r-- | src/client/app/common/views/widgets/instance.vue | 14 | ||||
| -rw-r--r-- | src/client/app/desktop/script.ts | 37 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/home.vue | 396 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/index.ts | 4 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/settings.vue | 19 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/ui.header.account.vue | 7 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/ui.header.nav.vue | 19 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/ui.sidebar.vue | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.column-core.vue (renamed from src/client/app/desktop/views/pages/deck/deck.column-core.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.column.vue (renamed from src/client/app/desktop/views/pages/deck/deck.column.vue) | 11 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.direct-column.vue (renamed from src/client/app/desktop/views/pages/deck/deck.direct-column.vue) | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.direct.vue (renamed from src/client/app/desktop/views/pages/deck/deck.direct.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.favorites-column.vue | 88 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.hashtag-column.vue | 119 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.hashtag-tl.vue (renamed from src/client/app/desktop/views/pages/deck/deck.hashtag-tl.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.list-tl.vue (renamed from src/client/app/desktop/views/pages/deck/deck.list-tl.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.mentions-column.vue (renamed from src/client/app/desktop/views/pages/deck/deck.mentions-column.vue) | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.mentions.vue (renamed from src/client/app/desktop/views/pages/deck/deck.mentions.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.note-column.vue (renamed from src/client/app/desktop/views/pages/deck/deck.note-column.vue) | 33 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.notes.vue (renamed from src/client/app/desktop/views/pages/deck/deck.notes.vue) | 6 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.notification.vue (renamed from src/client/app/desktop/views/pages/deck/deck.notification.vue) | 4 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.notifications-column.vue (renamed from src/client/app/desktop/views/pages/deck/deck.notifications-column.vue) | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.notifications.vue (renamed from src/client/app/desktop/views/pages/deck/deck.notifications.vue) | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.tl-column.vue (renamed from src/client/app/desktop/views/pages/deck/deck.tl-column.vue) | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.tl.vue (renamed from src/client/app/desktop/views/pages/deck/deck.tl.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.user-column.vue (renamed from src/client/app/desktop/views/pages/deck/deck.user-column.vue) | 224 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.vue (renamed from src/client/app/desktop/views/pages/deck/deck.vue) | 62 | ||||
| -rw-r--r-- | src/client/app/desktop/views/deck/deck.widgets-column.vue (renamed from src/client/app/desktop/views/pages/deck/deck.widgets-column.vue) | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/favorites.vue (renamed from src/client/app/desktop/views/pages/favorites.vue) | 26 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/home.vue | 400 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/note.vue (renamed from src/client/app/desktop/views/pages/note.vue) | 19 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/tag.vue (renamed from src/client/app/desktop/views/pages/tag.vue) | 21 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/timeline.core.vue (renamed from src/client/app/desktop/views/components/timeline.core.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/timeline.vue (renamed from src/client/app/desktop/views/components/timeline.vue) | 169 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/user/user.followers-you-know.vue (renamed from src/client/app/desktop/views/pages/user/user.followers-you-know.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/user/user.friends.vue (renamed from src/client/app/desktop/views/pages/user/user.friends.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/user/user.header.vue (renamed from src/client/app/desktop/views/pages/user/user.header.vue) | 19 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/user/user.integrations.integration.vue (renamed from src/client/app/desktop/views/pages/user/user.integrations.integration.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/user/user.integrations.vue (renamed from src/client/app/desktop/views/pages/user/user.integrations.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/user/user.photos.vue (renamed from src/client/app/desktop/views/pages/user/user.photos.vue) | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/user/user.timeline.vue (renamed from src/client/app/desktop/views/pages/user/user.timeline.vue) | 0 | ||||
| -rw-r--r-- | src/client/app/desktop/views/home/user/user.vue | 109 | ||||
| -rw-r--r-- | src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue | 112 | ||||
| -rw-r--r-- | src/client/app/desktop/views/pages/home-customize.vue | 3 | ||||
| -rw-r--r-- | src/client/app/desktop/views/pages/home.vue | 39 | ||||
| -rw-r--r-- | src/client/app/desktop/views/pages/index.vue | 25 | ||||
| -rw-r--r-- | src/client/app/desktop/views/pages/user/user.profile.vue | 66 | ||||
| -rw-r--r-- | src/client/app/desktop/views/pages/user/user.vue | 155 | ||||
| -rw-r--r-- | src/client/app/desktop/views/widgets/customize.vue | 21 | ||||
| -rw-r--r-- | src/client/app/desktop/views/widgets/index.ts | 2 | ||||
| -rw-r--r-- | src/client/app/init.ts | 9 | ||||
| -rw-r--r-- | src/client/app/mobile/views/pages/user/home.vue | 2 | ||||
| -rw-r--r-- | src/client/app/mobile/views/widgets/activity.vue | 2 | ||||
| -rw-r--r-- | src/client/app/store.ts | 9 |
59 files changed, 1119 insertions, 1199 deletions
diff --git a/src/client/app/mobile/views/components/activity.vue b/src/client/app/common/views/components/activity.vue index f06dddfc46..1e9f87cf04 100644 --- a/src/client/app/mobile/views/components/activity.vue +++ b/src/client/app/common/views/components/activity.vue @@ -1,5 +1,5 @@ <template> -<div class="mk-activity"> +<div> <div ref="chart"></div> </div> </template> @@ -9,7 +9,17 @@ import Vue from 'vue'; import ApexCharts from 'apexcharts'; export default Vue.extend({ - props: ['user'], + props: { + user: { + type: Object, + required: true + }, + limit: { + type: Number, + required: false, + default: 21 + } + }, data() { return { fetching: true, @@ -21,7 +31,7 @@ export default Vue.extend({ this.$root.api('charts/user/notes', { userId: this.user.id, span: 'day', - limit: 21 + limit: this.limit }).then(stats => { const normal = []; const reply = []; @@ -32,7 +42,7 @@ export default Vue.extend({ const m = now.getMonth(); const d = now.getDate(); - for (let i = 0; i < 21; i++) { + for (let i = 0; i < this.limit; i++) { const x = new Date(y, m, d - i); normal.push([ x, @@ -99,10 +109,3 @@ export default Vue.extend({ } }); </script> - -<style lang="stylus" scoped> -.mk-activity - max-width 600px - margin 0 auto - -</style> diff --git a/src/client/app/common/views/components/dummy.vue b/src/client/app/common/views/components/dummy.vue new file mode 100644 index 0000000000..5634efc509 --- /dev/null +++ b/src/client/app/common/views/components/dummy.vue @@ -0,0 +1,11 @@ +<template> +<div> + <slot></slot> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +export default Vue.extend({ +}); +</script> diff --git a/src/client/app/common/views/components/follow-button.vue b/src/client/app/common/views/components/follow-button.vue index 6d120f52b4..71d3a63e4c 100644 --- a/src/client/app/common/views/components/follow-button.vue +++ b/src/client/app/common/views/components/follow-button.vue @@ -1,8 +1,9 @@ <template> <button class="wfliddvnhxvyusikowhxozkyxyenqxqr" - :class="{ wait, block, mini, active: isFollowing || hasPendingFollowRequestFromYou }" + :class="{ wait, block, inline, mini, active: isFollowing || hasPendingFollowRequestFromYou }" @click="onClick" :disabled="wait" + :inline="inline" > <template v-if="!wait"> <fa :icon="iconAndText[0]"/> <template v-if="!mini">{{ iconAndText[1] }}</template> @@ -28,6 +29,11 @@ export default Vue.extend({ required: false, default: false }, + inline: { + type: Boolean, + required: false, + default: false + }, mini: { type: Boolean, required: false, @@ -128,6 +134,9 @@ export default Vue.extend({ border solid 1px var(--primary) border-radius 36px + &.inline + display inline-block + &.mini padding 0 min-width 0 diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index e6f93bb840..f60f7391d2 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -1,5 +1,6 @@ import Vue from 'vue'; +import dummy from './dummy.vue'; import userName from './user-name.vue'; import followButton from './follow-button.vue'; import error from './error.vue'; @@ -46,6 +47,7 @@ import formButton from './ui/form/button.vue'; import formRadio from './ui/form/radio.vue'; Vue.component('mfm', misskeyFlavoredMarkdown); +Vue.component('mk-dummy', dummy); Vue.component('mk-user-name', userName); Vue.component('mk-follow-button', followButton); Vue.component('mk-error', error); diff --git a/src/client/app/common/views/widgets/index.ts b/src/client/app/common/views/widgets/index.ts index 7fca79f1fc..6b198ccd51 100644 --- a/src/client/app/common/views/widgets/index.ts +++ b/src/client/app/common/views/widgets/index.ts @@ -13,6 +13,7 @@ import wSlideshow from './slideshow.vue'; import wTips from './tips.vue'; import wNav from './nav.vue'; import wHashtags from './hashtags.vue'; +import wInstance from './instance.vue'; Vue.component('mkw-analog-clock', wAnalogClock); Vue.component('mkw-nav', wNav); @@ -27,3 +28,4 @@ Vue.component('mkw-memo', wMemo); Vue.component('mkw-rss', wRss); Vue.component('mkw-version', wVersion); Vue.component('mkw-hashtags', wHashtags); +Vue.component('mkw-instance', wInstance); diff --git a/src/client/app/common/views/widgets/instance.vue b/src/client/app/common/views/widgets/instance.vue new file mode 100644 index 0000000000..1053235618 --- /dev/null +++ b/src/client/app/common/views/widgets/instance.vue @@ -0,0 +1,14 @@ +<template> +<div class="mkw-instance"> + <mk-widget-container> + <mk-instance/> + </mk-widget-container> +</div> +</template> + +<script lang="ts"> +import define from '../../../common/define-widget'; +export default define({ + name: 'instance' +}); +</script> diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts index 05cd79f706..26fe273394 100644 --- a/src/client/app/desktop/script.ts +++ b/src/client/app/desktop/script.ts @@ -12,19 +12,13 @@ import init from '../init'; import fuckAdBlock from '../common/scripts/fuck-ad-block'; import composeNotification from '../common/scripts/compose-notification'; -import MkIndex from './views/pages/index.vue'; -import MkHome from './views/pages/home.vue'; -import MkDeck from './views/pages/deck/deck.vue'; -import MkUser from './views/pages/user/user.vue'; +import MkHome from './views/home/home.vue'; +import MkDeck from './views/deck/deck.vue'; import MkUserFollowingOrFollowers from './views/pages/user-following-or-followers.vue'; -import MkFavorites from './views/pages/favorites.vue'; import MkSelectDrive from './views/pages/selectdrive.vue'; import MkDrive from './views/pages/drive.vue'; -import MkHomeCustomize from './views/pages/home-customize.vue'; import MkMessagingRoom from './views/pages/messaging-room.vue'; -import MkNote from './views/pages/note.vue'; import MkSearch from './views/pages/search.vue'; -import MkTag from './views/pages/tag.vue'; import MkReversi from './views/pages/games/reversi.vue'; import MkShare from './views/pages/share.vue'; import MkFollow from '../common/views/pages/follow.vue'; @@ -36,6 +30,7 @@ import PostFormWindow from './views/components/post-form-window.vue'; import RenoteFormWindow from './views/components/renote-form-window.vue'; import MkChooseFileFromDriveWindow from './views/components/choose-file-from-drive-window.vue'; import MkChooseFolderFromDriveWindow from './views/components/choose-folder-from-drive-window.vue'; +import MkHomeTimeline from './views/home/timeline.vue'; import Notification from './views/components/ui-notification.vue'; import { url } from '../config'; @@ -44,7 +39,7 @@ import MiOS from '../mios'; /** * init */ -init(async (launch) => { +init(async (launch, os) => { Vue.mixin({ methods: { $contextmenu(e, menu, opts?) { @@ -134,31 +129,37 @@ init(async (launch) => { const router = new VueRouter({ mode: 'history', routes: [ - { path: '/', name: 'index', component: MkIndex }, - { path: '/home', name: 'home', component: MkHome }, - { path: '/deck', name: 'deck', component: MkDeck }, - { path: '/i/customize-home', component: MkHomeCustomize }, - { path: '/i/favorites', component: MkFavorites }, + os.store.getters.isSignedIn && os.store.state.device.deckMode + ? { path: '/', name: 'index', component: MkDeck, children: [ + { 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: '/tags/:tag', name: 'tag', component: () => import('./views/deck/deck.hashtag-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: '', name: 'index', component: MkHomeTimeline }, + { 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: '/tags/:tag', name: 'tag', component: () => import('./views/home/tag.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/drive', component: MkDrive }, { path: '/i/drive/folder/:folder', component: MkDrive }, { path: '/i/settings', component: MkSettings }, { path: '/selectdrive', component: MkSelectDrive }, { path: '/search', component: MkSearch }, - { path: '/tags/:tag', name: 'tag', component: MkTag }, { path: '/share', component: MkShare }, { path: '/games/reversi/:game?', component: MkReversi }, - { path: '/@:user', name: 'user', component: MkUser }, { path: '/@:user/following', name: 'userFollowing', component: MkUserFollowingOrFollowers }, { path: '/@:user/followers', name: 'userFollowers', component: MkUserFollowingOrFollowers }, - { path: '/notes/:note', name: 'note', component: MkNote }, { path: '/authorize-follow', component: MkFollow }, { path: '*', component: MkNotFound } ] }); // Launch the app - const [app, os] = launch(router); + const [app, _] = launch(router); if (os.store.getters.isSignedIn) { /** diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue deleted file mode 100644 index 18cb215202..0000000000 --- a/src/client/app/desktop/views/components/home.vue +++ /dev/null @@ -1,396 +0,0 @@ -<template> -<div class="mk-home" :data-customize="customize"> - <div class="customize" v-if="customize"> - <router-link to="/"><fa icon="check"/>{{ $t('done') }}</router-link> - <div> - <div class="adder"> - <p>{{ $t('add-widget') }}</p> - <select v-model="widgetAdderSelected"> - <option value="profile">{{ $t('@.widgets.profile') }}</option> - <option value="analog-clock">{{ $t('@.widgets.analog-clock') }}</option> - <option value="calendar">{{ $t('@.widgets.calendar') }}</option> - <option value="timemachine">{{ $t('@.widgets.timemachine') }}</option> - <option value="activity">{{ $t('@.widgets.activity') }}</option> - <option value="rss">{{ $t('@.widgets.rss') }}</option> - <option value="trends">{{ $t('@.widgets.trends') }}</option> - <option value="photo-stream">{{ $t('@.widgets.photo-stream') }}</option> - <option value="slideshow">{{ $t('@.widgets.slideshow') }}</option> - <option value="version">{{ $t('@.widgets.version') }}</option> - <option value="broadcast">{{ $t('@.widgets.broadcast') }}</option> - <option value="notifications">{{ $t('@.widgets.notifications') }}</option> - <option value="users">{{ $t('@.widgets.users') }}</option> - <option value="polls">{{ $t('@.widgets.polls') }}</option> - <option value="post-form">{{ $t('@.widgets.post-form') }}</option> - <option value="messaging">{{ $t('@.widgets.messaging') }}</option> - <option value="memo">{{ $t('@.widgets.memo') }}</option> - <option value="hashtags">{{ $t('@.widgets.hashtags') }}</option> - <option value="posts-monitor">{{ $t('@.widgets.posts-monitor') }}</option> - <option value="server">{{ $t('@.widgets.server') }}</option> - <option value="nav">{{ $t('@.widgets.nav') }}</option> - <option value="tips">{{ $t('@.widgets.tips') }}</option> - </select> - <button @click="addWidget">{{ $t('add') }}</button> - </div> - <div class="trash"> - <x-draggable v-model="trash" :options="{ group: 'x' }" @add="onTrash"></x-draggable> - <p>{{ $t('@.trash') }}</p> - </div> - </div> - </div> - <div class="main" :class="{ side: widgets.left.length == 0 || widgets.right.length == 0 }"> - <template v-if="customize"> - <x-draggable v-for="place in ['left', 'right']" - :list="widgets[place]" - :class="place" - :data-place="place" - :options="{ group: 'x', animation: 150 }" - @sort="onWidgetSort" - :key="place" - > - <div v-for="widget in widgets[place]" class="customize-container" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)"> - <component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="desktop"/> - </div> - </x-draggable> - <div class="main"> - <a @click="hint">{{ $t('@.customization-tips.title') }}</a> - <div> - <mk-post-form v-if="$store.state.settings.showPostFormOnTopOfTl"/> - <mk-timeline ref="tl" @loaded="onTlLoaded"/> - </div> - </div> - </template> - <template v-else> - <div v-for="place in ['left', 'right']" :class="place"> - <component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp" platform="desktop"/> - </div> - <div class="main"> - <mk-post-form class="form" v-if="$store.state.settings.showPostFormOnTopOfTl"/> - <mk-timeline class="tl" ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/> - </div> - </template> - </div> -</div> -</template> - -<script lang="ts"> -import Vue from 'vue'; -import i18n from '../../../i18n'; -import * as XDraggable from 'vuedraggable'; -import * as uuid from 'uuid'; - -const defaultDesktopHomeWidgets = { - left: [ - 'profile', - 'calendar', - 'activity', - 'rss', - 'hashtags', - 'photo-stream', - 'version' - ], - right: [ - 'broadcast', - 'notifications', - 'users', - 'polls', - 'server', - 'nav', - 'tips' - ] -}; - -//#region Construct home data -const _defaultDesktopHomeWidgets = []; - -for (const widget of defaultDesktopHomeWidgets.left) { - _defaultDesktopHomeWidgets.push({ - name: widget, - id: uuid(), - place: 'left', - data: {} - }); -} - -for (const widget of defaultDesktopHomeWidgets.right) { - _defaultDesktopHomeWidgets.push({ - name: widget, - id: uuid(), - place: 'right', - data: {} - }); -} -//#endregion - -export default Vue.extend({ - i18n: i18n('desktop/views/components/home.vue'), - components: { - XDraggable - }, - - props: { - customize: { - type: Boolean, - default: false - }, - mode: { - type: String, - default: 'timeline' - } - }, - - data() { - return { - connection: null, - widgetAdderSelected: null, - trash: [] - }; - }, - - computed: { - home(): any[] { - return this.$store.state.settings.home || []; - }, - left(): any[] { - return this.home.filter(w => w.place == 'left'); - }, - right(): any[] { - return this.home.filter(w => w.place == 'right'); - }, - widgets(): any { - return { - left: this.left, - right: this.right - }; - } - }, - - created() { - if (this.$store.state.settings.home == null) { - this.$root.api('i/update_home', { - home: _defaultDesktopHomeWidgets - }).then(() => { - this.$store.commit('settings/setHome', _defaultDesktopHomeWidgets); - }); - } - }, - - mounted() { - this.connection = this.$root.stream.useSharedConnection('main'); - }, - - beforeDestroy() { - this.connection.dispose(); - }, - - methods: { - hint() { - this.$root.dialog({ - title: this.$t('@.customization-tips.title'), - text: this.$t('@.customization-tips.paragraph') - }); - }, - - onTlLoaded() { - this.$emit('loaded'); - }, - - onWidgetContextmenu(widgetId) { - const w = (this.$refs[widgetId] as any)[0]; - if (w.func) w.func(); - }, - - onWidgetSort() { - this.saveHome(); - }, - - onTrash(evt) { - this.saveHome(); - }, - - addWidget() { - this.$store.dispatch('settings/addHomeWidget', { - name: this.widgetAdderSelected, - id: uuid(), - place: 'left', - data: {} - }); - }, - - saveHome() { - const left = this.widgets.left; - const right = this.widgets.right; - this.$store.commit('settings/setHome', left.concat(right)); - for (const w of left) w.place = 'left'; - for (const w of right) w.place = 'right'; - this.$root.api('i/update_home', { - home: this.home - }); - }, - - warp(date) { - (this.$refs.tl as any).warp(date); - }, - - focus() { - (this.$refs.tl as any).focus(); - } - } -}); -</script> - -<style lang="stylus" scoped> -.mk-home - display block - - &[data-customize] - padding-top 48px - background-image url('/assets/desktop/grid.svg') - - > .main > .main - > a - display block - margin-bottom 8px - text-align center - - > div - cursor not-allowed !important - - > * - pointer-events none - - &:not([data-customize]) - > .main > *:empty - display none - - > .customize - position fixed - z-index 1000 - top 0 - left 0 - width 100% - height 48px - color var(--text) - background var(--desktopHeaderBg) - box-shadow 0 1px 1px rgba(#000, 0.075) - - > a - display block - position absolute - z-index 1001 - top 0 - right 0 - padding 0 16px - line-height 48px - text-decoration none - color var(--primaryForeground) - background var(--primary) - transition background 0.1s ease - - &:hover - background var(--primaryLighten10) - - &:active - background var(--primaryDarken10) - transition background 0s ease - - > [data-icon] - margin-right 8px - - > div - display flex - margin 0 auto - max-width 1220px - 32px - - > div - width 50% - - &.adder - > p - display inline - line-height 48px - - &.trash - border-left solid 1px var(--faceDivider) - - > div - width 100% - height 100% - - > p - position absolute - top 0 - left 0 - width 100% - line-height 48px - margin 0 - text-align center - pointer-events none - - > .main - display flex - justify-content center - margin 0 auto - max-width 1240px - - > * - .customize-container - cursor move - border-radius 6px - - &:hover - box-shadow 0 0 8px rgba(64, 120, 200, 0.3) - - > * - pointer-events none - - > .main - padding 16px - width calc(100% - 280px * 2) - order 2 - - > .form - margin-bottom 16px - box-shadow var(--shadow) - border-radius var(--round) - - &.side - > .main - width calc(100% - 280px) - max-width 680px - - > *:not(.main) - width 280px - padding 16px 0 16px 0 - - > *:not(:last-child) - margin-bottom 16px - - > .left - padding-left 16px - order 1 - - > .right - padding-right 16px - order 3 - - &.side - @media (max-width 1000px) - > *:not(.main) - display none - - > .main - width 100% - max-width 700px - margin 0 auto - - &:not(.side) - @media (max-width 1200px) - > *:not(.main) - display none - - > .main - width 100% - max-width 700px - margin 0 auto - -</style> diff --git a/src/client/app/desktop/views/components/index.ts b/src/client/app/desktop/views/components/index.ts index 2edc8117a8..0bc6fa9af4 100644 --- a/src/client/app/desktop/views/components/index.ts +++ b/src/client/app/desktop/views/components/index.ts @@ -2,8 +2,6 @@ import Vue from 'vue'; import ui from './ui.vue'; import uiNotification from './ui-notification.vue'; -import home from './home.vue'; -import timeline from './timeline.vue'; import notes from './notes.vue'; import subNoteContent from './sub-note-content.vue'; import window from './window.vue'; @@ -24,8 +22,6 @@ import widgetContainer from './widget-container.vue'; Vue.component('mk-ui', ui); Vue.component('mk-ui-notification', uiNotification); -Vue.component('mk-home', home); -Vue.component('mk-timeline', timeline); Vue.component('mk-notes', notes); Vue.component('mk-sub-note-content', subNoteContent); Vue.component('mk-window', window); diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue index 3452122b9a..e4e7830a16 100644 --- a/src/client/app/desktop/views/components/settings.vue +++ b/src/client/app/desktop/views/components/settings.vue @@ -31,9 +31,6 @@ <ui-switch v-model="autoPopout">{{ $t('auto-popout') }} <span slot="desc">{{ $t('auto-popout-desc') }}</span> </ui-switch> - <ui-switch v-model="deckNav">{{ $t('deck-nav') }} - <span slot="desc">{{ $t('deck-nav-desc') }}</span> - </ui-switch> <ui-switch v-model="keepCw">{{ $t('keep-cw') }} <span slot="desc">{{ $t('keep-cw-desc') }}</span> </ui-switch> @@ -90,9 +87,6 @@ <ui-radio v-model="navbar" value="right">{{ $t('navbar-position-right') }}</ui-radio> </section> <section> - <ui-switch v-model="deckDefault">{{ $t('deck-default') }}</ui-switch> - </section> - <section> <ui-switch v-model="darkmode">{{ $t('dark-mode') }}</ui-switch> <ui-switch v-model="useShadow">{{ $t('use-shadow') }}</ui-switch> <ui-switch v-model="roundedCorners">{{ $t('rounded-corners') }}</ui-switch> @@ -337,11 +331,6 @@ export default Vue.extend({ set(value) { this.$store.commit('device/set', { key: 'autoPopout', value }); } }, - deckNav: { - get() { return this.$store.state.settings.deckNav; }, - set(value) { this.$store.commit('settings/set', { key: 'deckNav', value }); } - }, - keepCw: { get() { return this.$store.state.settings.keepCw; }, set(value) { this.$store.commit('settings/set', { key: 'keepCw', value }); } @@ -367,11 +356,6 @@ export default Vue.extend({ set(value) { this.$store.commit('device/set', { key: 'deckColumnWidth', value }); } }, - deckDefault: { - get() { return this.$store.state.device.deckDefault; }, - set(value) { this.$store.commit('device/set', { key: 'deckDefault', value }); } - }, - enableSounds: { get() { return this.$store.state.device.enableSounds; }, set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); } @@ -534,8 +518,7 @@ export default Vue.extend({ }, methods: { customizeHome() { - this.$router.push('/i/customize-home'); - this.$emit('done'); + location.href = '/?customize'; }, updateWallpaper() { this.$chooseDriveFile({ diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue index bc7a8b2231..4a3cc71548 100644 --- a/src/client/app/desktop/views/components/ui.header.account.vue +++ b/src/client/app/desktop/views/components/ui.header.account.vue @@ -45,13 +45,6 @@ </ul> <ul> <li> - <router-link to="/i/customize-home"> - <i><fa icon="wrench"/></i> - <span>{{ $t('customize') }}</span> - <i><fa icon="angle-right"/></i> - </router-link> - </li> - <li> <router-link to="/i/settings"> <i><fa icon="cog"/></i> <span>{{ $t('settings') }}</span> diff --git a/src/client/app/desktop/views/components/ui.header.nav.vue b/src/client/app/desktop/views/components/ui.header.nav.vue index 8e78829de3..44659eb0d8 100644 --- a/src/client/app/desktop/views/components/ui.header.nav.vue +++ b/src/client/app/desktop/views/components/ui.header.nav.vue @@ -2,20 +2,20 @@ <div class="nav"> <ul> <template v-if="$store.getters.isSignedIn"> - <template v-if="$store.state.device.deckDefault"> - <li class="deck" :class="{ active: $route.name == 'deck' || $route.name == 'index' }" @click="goToTop"> + <template v-if="$store.state.device.deckMode"> + <li class="deck active" @click="goToTop"> <router-link to="/"><fa icon="columns"/><p>{{ $t('deck') }}</p></router-link> </li> - <li class="home" :class="{ active: $route.name == 'home' }" @click="goToTop"> - <router-link to="/home"><fa icon="home"/><p>{{ $t('home') }}</p></router-link> + <li class="home"> + <a @click="toggleDeckMode(false)"><fa icon="home"/><p>{{ $t('home') }}</p></a> </li> </template> <template v-else> - <li class="home" :class="{ active: $route.name == 'home' || $route.name == 'index' }" @click="goToTop"> + <li class="home active" @click="goToTop"> <router-link to="/"><fa icon="home"/><p>{{ $t('home') }}</p></router-link> </li> - <li class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop"> - <router-link to="/deck"><fa icon="columns"/><p>{{ $t('deck') }}</p></router-link> + <li class="deck"> + <a @click="toggleDeckMode(true)"><fa icon="columns"/><p>{{ $t('deck') }}</p></a> </li> </template> <li class="messaging"> @@ -70,6 +70,11 @@ export default Vue.extend({ } }, methods: { + toggleDeckMode(deck) { + this.$store.commit('device/set', { key: 'deckMode', value: deck }); + location.reload(); + }, + onReversiInvited() { this.hasGameInvitations = true; }, diff --git a/src/client/app/desktop/views/components/ui.sidebar.vue b/src/client/app/desktop/views/components/ui.sidebar.vue index 8b5f14290c..ec6b056595 100644 --- a/src/client/app/desktop/views/components/ui.sidebar.vue +++ b/src/client/app/desktop/views/components/ui.sidebar.vue @@ -6,7 +6,7 @@ </div> <div class="nav" v-if="$store.getters.isSignedIn"> - <template v-if="$store.state.device.deckDefault"> + <template v-if="$store.state.device.deckMode"> <div class="deck" :class="{ active: $route.name == 'deck' || $route.name == 'index' }" @click="goToTop"> <router-link to="/"><fa icon="columns"/></router-link> </div> diff --git a/src/client/app/desktop/views/pages/deck/deck.column-core.vue b/src/client/app/desktop/views/deck/deck.column-core.vue index 974c58235d..974c58235d 100644 --- a/src/client/app/desktop/views/pages/deck/deck.column-core.vue +++ b/src/client/app/desktop/views/deck/deck.column-core.vue diff --git a/src/client/app/desktop/views/pages/deck/deck.column.vue b/src/client/app/desktop/views/deck/deck.column.vue index 2acd2d0eda..f731e2e9b1 100644 --- a/src/client/app/desktop/views/pages/deck/deck.column.vue +++ b/src/client/app/desktop/views/deck/deck.column.vue @@ -27,9 +27,9 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; -import Menu from '../../../../common/views/components/menu.vue'; -import { countIf } from '../../../../../../prelude/array'; +import i18n from '../../../i18n'; +import Menu from '../../../common/views/components/menu.vue'; +import { countIf } from '../../../../../prelude/array'; export default Vue.extend({ i18n: i18n('deck'), @@ -245,10 +245,7 @@ export default Vue.extend({ }, close() { - this.$store.commit('device/set', { - key: 'deckTemporaryColumn', - value: null - }); + this.$router.push('/'); }, goTop() { diff --git a/src/client/app/desktop/views/pages/deck/deck.direct-column.vue b/src/client/app/desktop/views/deck/deck.direct-column.vue index cdeba95f5f..a1acf4e7f7 100644 --- a/src/client/app/desktop/views/pages/deck/deck.direct-column.vue +++ b/src/client/app/desktop/views/deck/deck.direct-column.vue @@ -8,7 +8,7 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; +import i18n from '../../../i18n'; import XColumn from './deck.column.vue'; import XDirect from './deck.direct.vue'; diff --git a/src/client/app/desktop/views/pages/deck/deck.direct.vue b/src/client/app/desktop/views/deck/deck.direct.vue index c6c2b99233..c6c2b99233 100644 --- a/src/client/app/desktop/views/pages/deck/deck.direct.vue +++ b/src/client/app/desktop/views/deck/deck.direct.vue diff --git a/src/client/app/desktop/views/deck/deck.favorites-column.vue b/src/client/app/desktop/views/deck/deck.favorites-column.vue new file mode 100644 index 0000000000..3c2b50dee8 --- /dev/null +++ b/src/client/app/desktop/views/deck/deck.favorites-column.vue @@ -0,0 +1,88 @@ +<template> +<x-column> + <span slot="header"> + <fa :icon="['fa', 'star']"/>{{ $t('favorites') }} + </span> + + <div> + <x-notes ref="timeline" :more="existMore ? 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'; + +const fetchLimit = 10; + +export default Vue.extend({ + i18n: i18n(), + + components: { + XColumn, + XNotes, + }, + + data() { + return { + fetching: true, + moreFetching: false, + existMore: false, + }; + }, + + mounted() { + this.fetch(); + }, + + methods: { + fetch() { + this.fetching = true; + + (this.$refs.timeline as any).init(() => new Promise((res, rej) => { + this.$root.api('i/favorites', { + limit: fetchLimit + 1, + }).then(notes => { + if (notes.length == fetchLimit + 1) { + notes.pop(); + this.existMore = true; + } + res(notes.map(x => x.note)); + this.fetching = false; + this.$emit('loaded'); + }, rej); + })); + }, + + more() { + this.moreFetching = true; + + const promise = this.$root.api('i/favorites', { + limit: fetchLimit + 1, + untilId: (this.$refs.timeline as any).tail().id, + }); + + promise.then(notes => { + if (notes.length == fetchLimit + 1) { + notes.pop(); + } else { + this.existMore = false; + } + for (const n of notes) { + (this.$refs.timeline as any).append(n); + } + this.moreFetching = false; + }); + + return promise; + }, + + focus() { + this.$refs.timeline.focus(); + } + } +}); +</script> diff --git a/src/client/app/desktop/views/deck/deck.hashtag-column.vue b/src/client/app/desktop/views/deck/deck.hashtag-column.vue new file mode 100644 index 0000000000..ca2d8cdb8d --- /dev/null +++ b/src/client/app/desktop/views/deck/deck.hashtag-column.vue @@ -0,0 +1,119 @@ +<template> +<x-column> + <span slot="header"> + <fa icon="hashtag"/><span>{{ tag }}</span> + </span> + + <div class="xroyrflcmhhtmlwmyiwpfqiirqokfueb"> + <div ref="chart" class="chart"></div> + <x-hashtag-tl :tag-tl="tagTl" class="tl"/> + </div> +</x-column> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import XColumn from './deck.column.vue'; +import XHashtagTl from './deck.hashtag-tl.vue'; +import ApexCharts from 'apexcharts'; + +export default Vue.extend({ + components: { + XColumn, + XHashtagTl + }, + + computed: { + tag(): string { + return this.$route.params.tag; + }, + + tagTl(): any { + return { + query: [[this.tag]] + }; + } + }, + + watch: { + $route: 'fetch' + }, + + created() { + this.fetch(); + }, + + methods: { + fetch() { + this.$root.api('charts/hashtag', { + tag: this.tag, + span: 'hour', + limit: 24 + }).then(stats => { + const local = []; + const remote = []; + + const now = new Date(); + const y = now.getFullYear(); + const m = now.getMonth(); + const d = now.getDate(); + const h = now.getHours(); + + for (let i = 0; i < 24; i++) { + const x = new Date(y, m, d, h - i); + local.push([x, stats.local.count[i]]); + remote.push([x, stats.remote.count[i]]); + } + + const chart = new ApexCharts(this.$refs.chart, { + chart: { + type: 'area', + height: 70, + sparkline: { + enabled: true + }, + }, + grid: { + clipMarkers: false, + padding: { + top: 16, + right: 16, + bottom: 16, + left: 16 + } + }, + stroke: { + curve: 'straight', + width: 2 + }, + series: [{ + name: 'Local', + data: local + }, { + name: 'Remote', + data: remote + }], + xaxis: { + type: 'datetime', + } + }); + + chart.render(); + }); + } + } +}); +</script> + +<style lang="stylus" scoped> +.xroyrflcmhhtmlwmyiwpfqiirqokfueb + background var(--deckColumnBg) + + > .chart + margin-bottom 16px + background var(--face) + + > .tl + background var(--face) + +</style> diff --git a/src/client/app/desktop/views/pages/deck/deck.hashtag-tl.vue b/src/client/app/desktop/views/deck/deck.hashtag-tl.vue index 9a70733fda..9a70733fda 100644 --- a/src/client/app/desktop/views/pages/deck/deck.hashtag-tl.vue +++ b/src/client/app/desktop/views/deck/deck.hashtag-tl.vue diff --git a/src/client/app/desktop/views/pages/deck/deck.list-tl.vue b/src/client/app/desktop/views/deck/deck.list-tl.vue index 68fbbb3ff9..68fbbb3ff9 100644 --- a/src/client/app/desktop/views/pages/deck/deck.list-tl.vue +++ b/src/client/app/desktop/views/deck/deck.list-tl.vue diff --git a/src/client/app/desktop/views/pages/deck/deck.mentions-column.vue b/src/client/app/desktop/views/deck/deck.mentions-column.vue index 011a321c3a..1fce65ea70 100644 --- a/src/client/app/desktop/views/pages/deck/deck.mentions-column.vue +++ b/src/client/app/desktop/views/deck/deck.mentions-column.vue @@ -8,7 +8,7 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; +import i18n from '../../../i18n'; import XColumn from './deck.column.vue'; import XMentions from './deck.mentions.vue'; diff --git a/src/client/app/desktop/views/pages/deck/deck.mentions.vue b/src/client/app/desktop/views/deck/deck.mentions.vue index 5fcabde5d6..5fcabde5d6 100644 --- a/src/client/app/desktop/views/pages/deck/deck.mentions.vue +++ b/src/client/app/desktop/views/deck/deck.mentions.vue diff --git a/src/client/app/desktop/views/pages/deck/deck.note-column.vue b/src/client/app/desktop/views/deck/deck.note-column.vue index 74da48bffc..f365573538 100644 --- a/src/client/app/desktop/views/pages/deck/deck.note-column.vue +++ b/src/client/app/desktop/views/deck/deck.note-column.vue @@ -18,10 +18,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; +import i18n from '../../../i18n'; import XColumn from './deck.column.vue'; import XNotes from './deck.notes.vue'; -import XNote from '../../components/note.vue'; +import XNote from '../components/note.vue'; export default Vue.extend({ i18n: i18n(), @@ -31,13 +31,6 @@ export default Vue.extend({ XNote }, - props: { - noteId: { - type: String, - required: true - } - }, - data() { return { note: null, @@ -45,11 +38,25 @@ export default Vue.extend({ }; }, + watch: { + $route: 'fetch' + }, + created() { - this.$root.api('notes/show', { noteId: this.noteId }).then(note => { - this.note = note; - this.fetching = false; - }); + this.fetch(); + }, + + methods: { + fetch() { + this.fetching = true; + + this.$root.api('notes/show', { + noteId: this.$route.params.note + }).then(note => { + this.note = note; + this.fetching = false; + }); + } } }); </script> diff --git a/src/client/app/desktop/views/pages/deck/deck.notes.vue b/src/client/app/desktop/views/deck/deck.notes.vue index 54e01a0012..260d75a884 100644 --- a/src/client/app/desktop/views/pages/deck/deck.notes.vue +++ b/src/client/app/desktop/views/deck/deck.notes.vue @@ -38,10 +38,10 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; -import shouldMuteNote from '../../../../common/scripts/should-mute-note'; +import i18n from '../../../i18n'; +import shouldMuteNote from '../../../common/scripts/should-mute-note'; -import XNote from '../../components/note.vue'; +import XNote from '../components/note.vue'; const displayLimit = 20; diff --git a/src/client/app/desktop/views/pages/deck/deck.notification.vue b/src/client/app/desktop/views/deck/deck.notification.vue index c20fe87a4f..56915f2d9c 100644 --- a/src/client/app/desktop/views/pages/deck/deck.notification.vue +++ b/src/client/app/desktop/views/deck/deck.notification.vue @@ -96,8 +96,8 @@ <script lang="ts"> import Vue from 'vue'; -import getNoteSummary from '../../../../../../misc/get-note-summary'; -import XNote from '../../components/note.vue'; +import getNoteSummary from '../../../../../misc/get-note-summary'; +import XNote from '../components/note.vue'; export default Vue.extend({ components: { diff --git a/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue b/src/client/app/desktop/views/deck/deck.notifications-column.vue index 69da7919b6..00bf77cf89 100644 --- a/src/client/app/desktop/views/pages/deck/deck.notifications-column.vue +++ b/src/client/app/desktop/views/deck/deck.notifications-column.vue @@ -8,7 +8,7 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; +import i18n from '../../../i18n'; import XColumn from './deck.column.vue'; import XNotifications from './deck.notifications.vue'; diff --git a/src/client/app/desktop/views/pages/deck/deck.notifications.vue b/src/client/app/desktop/views/deck/deck.notifications.vue index 5b556b31c8..5130140685 100644 --- a/src/client/app/desktop/views/pages/deck/deck.notifications.vue +++ b/src/client/app/desktop/views/deck/deck.notifications.vue @@ -25,7 +25,7 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; +import i18n from '../../../i18n'; import XNotification from './deck.notification.vue'; const displayLimit = 20; diff --git a/src/client/app/desktop/views/pages/deck/deck.tl-column.vue b/src/client/app/desktop/views/deck/deck.tl-column.vue index bc5e045373..1dac733718 100644 --- a/src/client/app/desktop/views/pages/deck/deck.tl-column.vue +++ b/src/client/app/desktop/views/deck/deck.tl-column.vue @@ -38,7 +38,7 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; +import i18n from '../../../i18n'; import XColumn from './deck.column.vue'; import XTl from './deck.tl.vue'; import XListTl from './deck.list-tl.vue'; diff --git a/src/client/app/desktop/views/pages/deck/deck.tl.vue b/src/client/app/desktop/views/deck/deck.tl.vue index 4f5e3af197..4f5e3af197 100644 --- a/src/client/app/desktop/views/pages/deck/deck.tl.vue +++ b/src/client/app/desktop/views/deck/deck.tl.vue diff --git a/src/client/app/desktop/views/pages/deck/deck.user-column.vue b/src/client/app/desktop/views/deck/deck.user-column.vue index b3e92f3e8a..60b3d2f0d5 100644 --- a/src/client/app/desktop/views/pages/deck/deck.user-column.vue +++ b/src/client/app/desktop/views/deck/deck.user-column.vue @@ -93,13 +93,13 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; -import parseAcct from '../../../../../../misc/acct/parse'; +import i18n from '../../../i18n'; +import parseAcct from '../../../../../misc/acct/parse'; import XColumn from './deck.column.vue'; import XNotes from './deck.notes.vue'; -import XNote from '../../components/note.vue'; -import XUserMenu from '../../../../common/views/components/user-menu.vue'; -import { concat } from '../../../../../../prelude/array'; +import XNote from '../components/note.vue'; +import XUserMenu from '../../../common/views/components/user-menu.vue'; +import { concat } from '../../../../../prelude/array'; import ApexCharts from 'apexcharts'; const fetchLimit = 10; @@ -112,13 +112,6 @@ export default Vue.extend({ XNote }, - props: { - acct: { - type: String, - required: true - } - }, - data() { return { user: null, @@ -144,119 +137,128 @@ export default Vue.extend({ }, }, + watch: { + $route: 'fetch' + }, + created() { - this.$root.api('users/show', parseAcct(this.acct)).then(user => { - this.user = user; - this.fetching = false; + this.fetch(); + }, - this.$nextTick(() => { - (this.$refs.timeline as any).init(() => this.initTl()); - }); + methods: { + fetch() { + this.fetching = true; + this.$root.api('users/show', parseAcct(this.$route.params.user)).then(user => { + this.user = user; + this.fetching = false; - const image = [ - 'image/jpeg', - 'image/png', - 'image/gif' - ]; + this.$nextTick(() => { + (this.$refs.timeline as any).init(() => this.initTl()); + }); - this.$root.api('users/notes', { - userId: this.user.id, - fileType: image, - excludeNsfw: !this.$store.state.device.alwaysShowNsfw, - limit: 9, - untilDate: new Date().getTime() + 1000 * 86400 * 365 - }).then(notes => { - for (const note of notes) { - for (const file of note.files) { - file._note = note; + const image = [ + 'image/jpeg', + 'image/png', + 'image/gif' + ]; + + this.$root.api('users/notes', { + userId: this.user.id, + fileType: image, + excludeNsfw: !this.$store.state.device.alwaysShowNsfw, + limit: 9, + untilDate: new Date().getTime() + 1000 * 86400 * 365 + }).then(notes => { + for (const note of notes) { + for (const file of note.files) { + file._note = note; + } } - } - const files = concat(notes.map((n: any): any[] => n.files)); - this.images = files.filter(f => image.includes(f.type)).slice(0, 9); - }); + const files = concat(notes.map((n: any): any[] => n.files)); + this.images = files.filter(f => image.includes(f.type)).slice(0, 9); + }); - this.$root.api('charts/user/notes', { - userId: this.user.id, - span: 'day', - limit: 21 - }).then(stats => { - const normal = []; - const reply = []; - const renote = []; + this.$root.api('charts/user/notes', { + userId: this.user.id, + span: 'day', + limit: 21 + }).then(stats => { + const normal = []; + const reply = []; + const renote = []; - const now = new Date(); - const y = now.getFullYear(); - const m = now.getMonth(); - const d = now.getDate(); + 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); - normal.push([ - x, - stats.diffs.normal[i] - ]); - reply.push([ - x, - stats.diffs.reply[i] - ]); - renote.push([ - x, - stats.diffs.renote[i] - ]); - } + for (let i = 0; i < 21; 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 + const chart = new ApexCharts(this.$refs.chart, { + chart: { + type: 'bar', + stacked: true, + height: 100, + sparkline: { + enabled: true + }, }, - }, - plotOptions: { - bar: { - columnWidth: '90%' - } - }, - grid: { - clipMarkers: false, - padding: { - top: 16, - right: 16, - bottom: 16, - left: 16 - } - }, - tooltip: { - shared: true, - intersect: false - }, - series: [{ - name: 'Normal', - data: normal - }, { - name: 'Reply', - data: reply - }, { - name: 'Renote', - data: renote - }], - xaxis: { - type: 'datetime', - crosshairs: { - width: 1, - opacity: 1 + plotOptions: { + bar: { + columnWidth: '90%' + } + }, + grid: { + clipMarkers: false, + padding: { + top: 16, + right: 16, + bottom: 16, + left: 16 + } + }, + tooltip: { + shared: true, + intersect: false + }, + series: [{ + name: 'Normal', + data: normal + }, { + name: 'Reply', + data: reply + }, { + name: 'Renote', + data: renote + }], + xaxis: { + type: 'datetime', + crosshairs: { + width: 1, + opacity: 1 + } } - } - }); + }); - chart.render(); + chart.render(); + }); }); - }); - }, + }, - methods: { initTl() { return new Promise((res, rej) => { this.$root.api('users/notes', { diff --git a/src/client/app/desktop/views/pages/deck/deck.vue b/src/client/app/desktop/views/deck/deck.vue index 30b985e7e4..5af2075e4a 100644 --- a/src/client/app/desktop/views/pages/deck/deck.vue +++ b/src/client/app/desktop/views/deck/deck.vue @@ -9,11 +9,7 @@ </div> <x-column-core v-else :ref="ids[0]" :key="ids[0]" :column="columns.find(c => c.id == ids[0])" @parentFocus="moveFocus(ids[0], $event)"/> </template> - <template v-if="temporaryColumn"> - <x-user-column v-if="temporaryColumn.type == 'user'" :acct="temporaryColumn.acct" :key="temporaryColumn.acct"/> - <x-note-column v-else-if="temporaryColumn.type == 'note'" :note-id="temporaryColumn.noteId" :key="temporaryColumn.noteId"/> - <x-hashtag-column v-else-if="temporaryColumn.type == 'tag'" :tag="temporaryColumn.tag" :key="temporaryColumn.tag"/> - </template> + <router-view></router-view> <button ref="add" @click="add" :title="$t('@deck.add-column')"><fa icon="plus"/></button> </div> </mk-ui> @@ -21,20 +17,17 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; +import i18n from '../../../i18n'; import XColumnCore from './deck.column-core.vue'; -import Menu from '../../../../common/views/components/menu.vue'; -import MkUserListsWindow from '../../components/user-lists-window.vue'; +import Menu from '../../../common/views/components/menu.vue'; +import MkUserListsWindow from '../components/user-lists-window.vue'; import * as uuid from 'uuid'; export default Vue.extend({ i18n: i18n('deck'), components: { - XColumnCore, - XUserColumn: () => import('./deck.user-column.vue').then(m => m.default), - XNoteColumn: () => import('./deck.note-column.vue').then(m => m.default), - XHashtagColumn: () => import('./deck.hashtag-column.vue').then(m => m.default) + XColumnCore }, computed: { @@ -55,10 +48,6 @@ export default Vue.extend({ }; }, - temporaryColumn(): any { - return this.$store.state.device.deckTemporaryColumn; - }, - keymap(): any { return { 't': this.focus @@ -66,7 +55,7 @@ export default Vue.extend({ } }, - watch: { + watch: {/* temporaryColumn() { if (this.temporaryColumn != null) { this.$nextTick(() => { @@ -76,7 +65,7 @@ export default Vue.extend({ }); }); } - } + }*/ }, provide() { @@ -86,8 +75,6 @@ export default Vue.extend({ }, created() { - this.$store.commit('navHook', this.onNav); - if (this.$store.state.settings.deck == null) { const deck = { columns: [/*{ @@ -133,8 +120,6 @@ export default Vue.extend({ }, beforeDestroy() { - this.$store.commit('navHook', null); - document.documentElement.style.overflow = 'auto'; }, @@ -143,39 +128,6 @@ export default Vue.extend({ return this.$refs[id][0]; }, - onNav(to) { - if (!this.$store.state.settings.deckNav) return false; - - if (to.name == 'user') { - this.$store.commit('device/set', { - key: 'deckTemporaryColumn', - value: { - type: 'user', - acct: to.params.user - } - }); - return true; - } else if (to.name == 'note') { - this.$store.commit('device/set', { - key: 'deckTemporaryColumn', - value: { - type: 'note', - noteId: to.params.note - } - }); - return true; - } else if (to.name == 'tag') { - this.$store.commit('device/set', { - key: 'deckTemporaryColumn', - value: { - type: 'tag', - tag: to.params.tag - } - }); - return true; - } - }, - add() { this.$root.new(Menu, { source: this.$refs.add, diff --git a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue b/src/client/app/desktop/views/deck/deck.widgets-column.vue index 0798e2ccc7..2af2f1f05c 100644 --- a/src/client/app/desktop/views/pages/deck/deck.widgets-column.vue +++ b/src/client/app/desktop/views/deck/deck.widgets-column.vue @@ -50,7 +50,7 @@ <script lang="ts"> import Vue from 'vue'; -import i18n from '../../../../i18n'; +import i18n from '../../../i18n'; import XColumn from './deck.column.vue'; import * as XDraggable from 'vuedraggable'; import * as uuid from 'uuid'; diff --git a/src/client/app/desktop/views/pages/favorites.vue b/src/client/app/desktop/views/home/favorites.vue index 066ce3f53c..4a4fc9ad8f 100644 --- a/src/client/app/desktop/views/pages/favorites.vue +++ b/src/client/app/desktop/views/home/favorites.vue @@ -1,16 +1,14 @@ <template> -<mk-ui> - <main v-if="!fetching"> - <sequential-entrance animation="entranceFromTop" delay="25"> - <template v-for="favorite in favorites"> - <mk-note-detail class="post" :note="favorite.note" :key="favorite.note.id"/> - </template> - </sequential-entrance> - <div class="more" v-if="existMore"> - <ui-button inline @click="more">{{ $t('@.load-more') }}</ui-button> - </div> - </main> -</mk-ui> +<div class="ecsvsegy" v-if="!fetching"> + <sequential-entrance animation="entranceFromTop" delay="25"> + <template v-for="favorite in favorites"> + <mk-note-detail class="post" :note="favorite.note" :key="favorite.note.id"/> + </template> + </sequential-entrance> + <div class="more" v-if="existMore"> + <ui-button inline @click="more">{{ $t('@.load-more') }}</ui-button> + </div> +</div> </template> <script lang="ts"> @@ -72,10 +70,8 @@ export default Vue.extend({ </script> <style lang="stylus" scoped> -main +.ecsvsegy margin 0 auto - padding 16px - max-width 700px > * > .post margin-bottom 16px diff --git a/src/client/app/desktop/views/home/home.vue b/src/client/app/desktop/views/home/home.vue new file mode 100644 index 0000000000..5e265634fb --- /dev/null +++ b/src/client/app/desktop/views/home/home.vue @@ -0,0 +1,400 @@ +<template> +<component :is="customize ? 'mk-dummy' : 'mk-ui'" v-hotkey.global="keymap" v-if="$store.getters.isSignedIn || $route.name != 'index'"> + <div class="wqsofvpm" :data-customize="customize"> + <div class="customize" v-if="customize"> + <a @click="done()"><fa icon="check"/>{{ $t('done') }}</a> + <div> + <div class="adder"> + <p>{{ $t('add-widget') }}</p> + <select v-model="widgetAdderSelected"> + <option value="profile">{{ $t('@.widgets.profile') }}</option> + <option value="analog-clock">{{ $t('@.widgets.analog-clock') }}</option> + <option value="calendar">{{ $t('@.widgets.calendar') }}</option> + <option value="timemachine">{{ $t('@.widgets.timemachine') }}</option> + <option value="activity">{{ $t('@.widgets.activity') }}</option> + <option value="rss">{{ $t('@.widgets.rss') }}</option> + <option value="trends">{{ $t('@.widgets.trends') }}</option> + <option value="photo-stream">{{ $t('@.widgets.photo-stream') }}</option> + <option value="slideshow">{{ $t('@.widgets.slideshow') }}</option> + <option value="version">{{ $t('@.widgets.version') }}</option> + <option value="broadcast">{{ $t('@.widgets.broadcast') }}</option> + <option value="notifications">{{ $t('@.widgets.notifications') }}</option> + <option value="users">{{ $t('@.widgets.users') }}</option> + <option value="polls">{{ $t('@.widgets.polls') }}</option> + <option value="post-form">{{ $t('@.widgets.post-form') }}</option> + <option value="messaging">{{ $t('@.widgets.messaging') }}</option> + <option value="memo">{{ $t('@.widgets.memo') }}</option> + <option value="hashtags">{{ $t('@.widgets.hashtags') }}</option> + <option value="posts-monitor">{{ $t('@.widgets.posts-monitor') }}</option> + <option value="server">{{ $t('@.widgets.server') }}</option> + <option value="nav">{{ $t('@.widgets.nav') }}</option> + <option value="tips">{{ $t('@.widgets.tips') }}</option> + </select> + <button @click="addWidget">{{ $t('add') }}</button> + </div> + <div class="trash"> + <x-draggable v-model="trash" :options="{ group: 'x' }" @add="onTrash"></x-draggable> + <p>{{ $t('@.trash') }}</p> + </div> + </div> + </div> + <div class="main" :class="{ side: widgets.left.length == 0 || widgets.right.length == 0 }"> + <template v-if="customize"> + <x-draggable v-for="place in ['left', 'right']" + :list="widgets[place]" + :class="place" + :data-place="place" + :options="{ group: 'x', animation: 150 }" + @sort="onWidgetSort" + :key="place" + > + <div v-for="widget in widgets[place]" class="customize-container" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)"> + <component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true" platform="desktop"/> + </div> + </x-draggable> + <div class="main"> + <a @click="hint">{{ $t('@.customization-tips.title') }}</a> + <div> + <x-timeline/> + </div> + </div> + </template> + <template v-else> + <div v-for="place in ['left', 'right']" :class="place"> + <component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" platform="desktop"/> + </div> + <div class="main"> + <router-view ref="content"></router-view> + </div> + </template> + </div> + </div> +</component> +<x-welcome v-else/> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import i18n from '../../../i18n'; +import * as XDraggable from 'vuedraggable'; +import * as uuid from 'uuid'; +import XWelcome from '../pages/welcome.vue'; + +export default Vue.extend({ + i18n: i18n('desktop/views/components/home.vue'), + components: { + XDraggable, + XWelcome + }, + + data() { + return { + customize: window.location.search == '?customize', + connection: null, + widgetAdderSelected: null, + trash: [], + view: null + }; + }, + + computed: { + home(): any[] { + if (this.$store.getters.isSignedIn) { + return this.$store.state.settings.home || []; + } else { + return [{ + name: 'instance', + place: 'right' + }]; + } + }, + left(): any[] { + return this.home.filter(w => w.place == 'left'); + }, + right(): any[] { + return this.home.filter(w => w.place == 'right'); + }, + widgets(): any { + return { + left: this.left, + right: this.right + }; + }, + keymap(): any { + return { + 't': this.focus + }; + } + }, + + created() { + if (this.$store.getters.isSignedIn) { + const defaultDesktopHomeWidgets = { + left: [ + 'profile', + 'calendar', + 'activity', + 'rss', + 'hashtags', + 'photo-stream', + 'version' + ], + right: [ + 'customize', + 'broadcast', + 'notifications', + 'users', + 'polls', + 'server', + 'nav', + 'tips' + ] + }; + + //#region Construct home data + const _defaultDesktopHomeWidgets = []; + + for (const widget of defaultDesktopHomeWidgets.left) { + _defaultDesktopHomeWidgets.push({ + name: widget, + id: uuid(), + place: 'left', + data: {} + }); + } + + for (const widget of defaultDesktopHomeWidgets.right) { + _defaultDesktopHomeWidgets.push({ + name: widget, + id: uuid(), + place: 'right', + data: {} + }); + } + //#endregion + + if (this.$store.state.settings.home == null) { + this.$root.api('i/update_home', { + home: _defaultDesktopHomeWidgets + }).then(() => { + this.$store.commit('settings/setHome', _defaultDesktopHomeWidgets); + }); + } + } + }, + + mounted() { + this.connection = this.$root.stream.useSharedConnection('main'); + }, + + beforeDestroy() { + this.connection.dispose(); + }, + + methods: { + hint() { + this.$root.dialog({ + title: this.$t('@.customization-tips.title'), + text: this.$t('@.customization-tips.paragraph') + }); + }, + + onTlLoaded() { + this.$emit('loaded'); + }, + + onWidgetContextmenu(widgetId) { + const w = (this.$refs[widgetId] as any)[0]; + if (w.func) w.func(); + }, + + onWidgetSort() { + this.saveHome(); + }, + + onTrash(evt) { + this.saveHome(); + }, + + addWidget() { + this.$store.dispatch('settings/addHomeWidget', { + name: this.widgetAdderSelected, + id: uuid(), + place: 'left', + data: {} + }); + }, + + saveHome() { + const left = this.widgets.left; + const right = this.widgets.right; + this.$store.commit('settings/setHome', left.concat(right)); + for (const w of left) w.place = 'left'; + for (const w of right) w.place = 'right'; + this.$root.api('i/update_home', { + home: this.home + }); + }, + + done() { + location.href = '/'; + }, + + focus() { + (this.$refs.content as any).focus(); + } + } +}); +</script> + +<style lang="stylus" scoped> +.wqsofvpm + display block + + &[data-customize] + padding-top 48px + background-image url('/assets/desktop/grid.svg') + + > .main > .main + > a + display block + margin-bottom 8px + text-align center + + > div + cursor not-allowed !important + + > * + pointer-events none + + &:not([data-customize]) + > .main > *:not(.main):empty + display none + + > .customize + position fixed + z-index 1000 + top 0 + left 0 + width 100% + height 48px + color var(--text) + background var(--desktopHeaderBg) + box-shadow 0 1px 1px rgba(#000, 0.075) + + > a + display block + position absolute + z-index 1001 + top 0 + right 0 + padding 0 16px + line-height 48px + text-decoration none + color var(--primaryForeground) + background var(--primary) + transition background 0.1s ease + + &:hover + background var(--primaryLighten10) + + &:active + background var(--primaryDarken10) + transition background 0s ease + + > [data-icon] + margin-right 8px + + > div + display flex + margin 0 auto + max-width 1220px - 32px + + > div + width 50% + + &.adder + > p + display inline + line-height 48px + + &.trash + border-left solid 1px var(--faceDivider) + + > div + width 100% + height 100% + + > p + position absolute + top 0 + left 0 + width 100% + line-height 48px + margin 0 + text-align center + pointer-events none + + > .main + display flex + justify-content center + margin 0 auto + max-width 1240px + + > * + .customize-container + cursor move + border-radius 6px + + &:hover + box-shadow 0 0 8px rgba(64, 120, 200, 0.3) + + > * + pointer-events none + + > .main + padding 16px + width calc(100% - 280px * 2) + order 2 + + &.side + > .main + width calc(100% - 280px) + max-width 680px + + > *:not(.main) + width 280px + padding 16px 0 16px 0 + + > *:not(:last-child) + margin-bottom 16px + + > .left + padding-left 16px + order 1 + + > .right + padding-right 16px + order 3 + + &.side + @media (max-width 1000px) + > *:not(.main) + display none + + > .main + width 100% + max-width 700px + margin 0 auto + + &:not(.side) + @media (max-width 1200px) + > *:not(.main) + display none + + > .main + width 100% + max-width 700px + margin 0 auto + +</style> diff --git a/src/client/app/desktop/views/pages/note.vue b/src/client/app/desktop/views/home/note.vue index 46d39d0b4a..90d3fd4357 100644 --- a/src/client/app/desktop/views/pages/note.vue +++ b/src/client/app/desktop/views/home/note.vue @@ -1,13 +1,11 @@ <template> -<mk-ui> - <main v-if="!fetching"> - <mk-note-detail :note="note"/> - <footer> - <router-link v-if="note.next" :to="note.next"><fa icon="angle-left"/> {{ $t('next') }}</router-link> - <router-link v-if="note.prev" :to="note.prev">{{ $t('prev') }} <fa icon="angle-right"/></router-link> - </footer> - </main> -</mk-ui> +<div v-if="!fetching" class="kcthdwmv"> + <mk-note-detail :note="note"/> + <footer> + <router-link v-if="note.next" :to="note.next"><fa icon="angle-left"/> {{ $t('next') }}</router-link> + <router-link v-if="note.prev" :to="note.prev">{{ $t('prev') }} <fa icon="angle-right"/></router-link> + </footer> +</div> </template> <script lang="ts"> @@ -48,8 +46,7 @@ export default Vue.extend({ </script> <style lang="stylus" scoped> -main - padding 16px +.kcthdwmv text-align center > footer diff --git a/src/client/app/desktop/views/pages/tag.vue b/src/client/app/desktop/views/home/tag.vue index 6e5db18af0..9e0978fb09 100644 --- a/src/client/app/desktop/views/pages/tag.vue +++ b/src/client/app/desktop/views/home/tag.vue @@ -1,11 +1,8 @@ <template> -<mk-ui> - <header :class="$style.header"> - <h1>#{{ $route.params.tag }}</h1> - </header> +<div> <p :class="$style.empty" v-if="!fetching && empty"><fa icon="search"/> {{ $t('no-posts-found', { q: $route.params.tag }) }}</p> <mk-notes ref="timeline" :class="$style.notes" :more="existMore ? more : null"/> -</mk-ui> +</div> </template> <script lang="ts"> @@ -96,17 +93,11 @@ export default Vue.extend({ </script> <style lang="stylus" module> -.header - width 100% - max-width 600px - margin 0 auto - color #555 - .notes - width 600px - margin 0 auto - border solid 1px rgba(#000, 0.075) - border-radius 6px + background var(--face) + box-shadow var(--shadow) + border-radius var(--round) + overflow hidden overflow hidden .empty diff --git a/src/client/app/desktop/views/components/timeline.core.vue b/src/client/app/desktop/views/home/timeline.core.vue index 63bc20dc28..63bc20dc28 100644 --- a/src/client/app/desktop/views/components/timeline.core.vue +++ b/src/client/app/desktop/views/home/timeline.core.vue diff --git a/src/client/app/desktop/views/components/timeline.vue b/src/client/app/desktop/views/home/timeline.vue index 0a91cfb59d..2f42b9723f 100644 --- a/src/client/app/desktop/views/components/timeline.vue +++ b/src/client/app/desktop/views/home/timeline.vue @@ -1,27 +1,30 @@ <template> <div class="mk-timeline"> - <header> - <span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span> - <span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span> - <span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('hybrid') }}</span> - <span :data-active="src == 'global'" @click="src = 'global'" v-if="enableGlobalTimeline"><fa icon="globe"/> {{ $t('global') }}</span> - <span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl"><fa icon="hashtag"/> {{ tagTl.title }}</span> - <span :data-active="src == 'list'" @click="src = 'list'" v-if="list"><fa icon="list"/> {{ list.title }}</span> - <div class="buttons"> - <button :data-active="src == 'mentions'" @click="src = 'mentions'" :title="$t('mentions')"><fa icon="at"/><i class="badge" v-if="$store.state.i.hasUnreadMentions"><fa icon="circle"/></i></button> - <button :data-active="src == 'messages'" @click="src = 'messages'" :title="$t('messages')"><fa :icon="['far', 'envelope']"/><i class="badge" v-if="$store.state.i.hasUnreadSpecifiedNotes"><fa icon="circle"/></i></button> - <button @click="chooseTag" :title="$t('hashtag')" ref="tagButton"><fa icon="hashtag"/></button> - <button @click="chooseList" :title="$t('list')" ref="listButton"><fa icon="list"/></button> - </div> - </header> - <x-core v-if="src == 'home'" ref="tl" key="home" src="home"/> - <x-core v-if="src == 'local'" ref="tl" key="local" src="local"/> - <x-core v-if="src == 'hybrid'" ref="tl" key="hybrid" src="hybrid"/> - <x-core v-if="src == 'global'" ref="tl" key="global" src="global"/> - <x-core v-if="src == 'mentions'" ref="tl" key="mentions" src="mentions"/> - <x-core v-if="src == 'messages'" ref="tl" key="messages" src="messages"/> - <x-core v-if="src == 'tag'" ref="tl" key="tag" src="tag" :tag-tl="tagTl"/> - <mk-user-list-timeline v-if="src == 'list'" ref="tl" :key="list.id" :list="list"/> + <mk-post-form class="form" v-if="$store.state.settings.showPostFormOnTopOfTl"/> + <div class="main"> + <header> + <span :data-active="src == 'home'" @click="src = 'home'"><fa icon="home"/> {{ $t('home') }}</span> + <span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline"><fa :icon="['far', 'comments']"/> {{ $t('local') }}</span> + <span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline"><fa icon="share-alt"/> {{ $t('hybrid') }}</span> + <span :data-active="src == 'global'" @click="src = 'global'" v-if="enableGlobalTimeline"><fa icon="globe"/> {{ $t('global') }}</span> + <span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl"><fa icon="hashtag"/> {{ tagTl.title }}</span> + <span :data-active="src == 'list'" @click="src = 'list'" v-if="list"><fa icon="list"/> {{ list.title }}</span> + <div class="buttons"> + <button :data-active="src == 'mentions'" @click="src = 'mentions'" :title="$t('mentions')"><fa icon="at"/><i class="badge" v-if="$store.state.i.hasUnreadMentions"><fa icon="circle"/></i></button> + <button :data-active="src == 'messages'" @click="src = 'messages'" :title="$t('messages')"><fa :icon="['far', 'envelope']"/><i class="badge" v-if="$store.state.i.hasUnreadSpecifiedNotes"><fa icon="circle"/></i></button> + <button @click="chooseTag" :title="$t('hashtag')" ref="tagButton"><fa icon="hashtag"/></button> + <button @click="chooseList" :title="$t('list')" ref="listButton"><fa icon="list"/></button> + </div> + </header> + <x-core v-if="src == 'home'" ref="tl" key="home" src="home"/> + <x-core v-if="src == 'local'" ref="tl" key="local" src="local"/> + <x-core v-if="src == 'hybrid'" ref="tl" key="hybrid" src="hybrid"/> + <x-core v-if="src == 'global'" ref="tl" key="global" src="global"/> + <x-core v-if="src == 'mentions'" ref="tl" key="mentions" src="mentions"/> + <x-core v-if="src == 'messages'" ref="tl" key="messages" src="messages"/> + <x-core v-if="src == 'tag'" ref="tl" key="tag" src="tag" :tag-tl="tagTl"/> + <mk-user-list-timeline v-if="src == 'list'" ref="tl" :key="list.id" :list="list"/> + </div> </div> </template> @@ -30,7 +33,7 @@ import Vue from 'vue'; import i18n from '../../../i18n'; import XCore from './timeline.core.vue'; import Menu from '../../../common/views/components/menu.vue'; -import MkSettingsWindow from './settings-window.vue'; +import MkSettingsWindow from '../components/settings-window.vue'; export default Vue.extend({ i18n: i18n('desktop/views/components/timeline.vue'), @@ -184,81 +187,87 @@ export default Vue.extend({ <style lang="stylus" scoped> .mk-timeline - background var(--face) - box-shadow var(--shadow) - border-radius var(--round) - overflow hidden + > .form + margin-bottom 16px + box-shadow var(--shadow) + border-radius var(--round) - > header - padding 0 8px - z-index 10 - background var(--faceHeader) - box-shadow 0 var(--lineWidth) var(--desktopTimelineHeaderShadow) + > .main + background var(--face) + box-shadow var(--shadow) + border-radius var(--round) + overflow hidden - > .buttons - position absolute - z-index 2 - top 0 - right 0 - padding-right 8px + > header + padding 0 8px + z-index 10 + background var(--faceHeader) + box-shadow 0 var(--lineWidth) var(--desktopTimelineHeaderShadow) - > button - padding 0 8px - font-size 0.9em - line-height 42px - color var(--faceTextButton) + > .buttons + position absolute + z-index 2 + top 0 + right 0 + padding-right 8px + + > button + padding 0 8px + font-size 0.9em + line-height 42px + color var(--faceTextButton) + + > .badge + position absolute + top -4px + right 4px + font-size 10px + color var(--notificationIndicator) + + &:hover + color var(--faceTextButtonHover) - > .badge - position absolute - top -4px - right 4px - font-size 10px - color var(--notificationIndicator) + &[data-active] + color var(--primary) + cursor default - &:hover - color var(--faceTextButtonHover) + &:before + content "" + display block + position absolute + bottom 0 + left 0 + width 100% + height 2px + background var(--primary) + + > span + display inline-block + padding 0 10px + line-height 42px + font-size 12px + user-select none &[data-active] color var(--primary) cursor default + font-weight bold &:before content "" display block position absolute bottom 0 - left 0 - width 100% + left -8px + width calc(100% + 16px) height 2px background var(--primary) - > span - display inline-block - padding 0 10px - line-height 42px - font-size 12px - user-select none - - &[data-active] - color var(--primary) - cursor default - font-weight bold - - &:before - content "" - display block - position absolute - bottom 0 - left -8px - width calc(100% + 16px) - height 2px - background var(--primary) - - &:not([data-active]) - color var(--desktopTimelineSrc) - cursor pointer + &:not([data-active]) + color var(--desktopTimelineSrc) + cursor pointer - &:hover - color var(--desktopTimelineSrcHover) + &:hover + color var(--desktopTimelineSrcHover) </style> diff --git a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue b/src/client/app/desktop/views/home/user/user.followers-you-know.vue index 53949a7943..53949a7943 100644 --- a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue +++ b/src/client/app/desktop/views/home/user/user.followers-you-know.vue diff --git a/src/client/app/desktop/views/pages/user/user.friends.vue b/src/client/app/desktop/views/home/user/user.friends.vue index e3182e91fa..e3182e91fa 100644 --- a/src/client/app/desktop/views/pages/user/user.friends.vue +++ b/src/client/app/desktop/views/home/user/user.friends.vue diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/home/user/user.header.vue index 8352f662c0..a0d141fb97 100644 --- a/src/client/app/desktop/views/pages/user/user.header.vue +++ b/src/client/app/desktop/views/home/user/user.header.vue @@ -15,6 +15,13 @@ </div> <mk-avatar class="avatar" :user="user" :disable-preview="true"/> <div class="body"> + <div class="actions" v-if="$store.getters.isSignedIn"> + <template v-if="$store.state.i.id != user.id"> + <p class="followed" v-if="user.isFollowed">{{ $t('follows-you') }}</p> + <mk-follow-button :user="user" :inline="true" class="follow"/> + </template> + <ui-button @click="menu" ref="menu" :inline="true"><fa icon="ellipsis-h"/></ui-button> + </div> <div class="description"> <mfm v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> </div> @@ -45,6 +52,7 @@ import Vue from 'vue'; import i18n from '../../../../i18n'; import * as age from 's-age'; +import XUserMenu from '../../../../common/views/components/user-menu.vue'; export default Vue.extend({ i18n: i18n('desktop/views/pages/user/user.header.vue'), @@ -99,6 +107,13 @@ export default Vue.extend({ this.$updateBanner().then(i => { this.user.bannerUrl = i.bannerUrl; }); + }, + + menu() { + this.$root.new(XUserMenu, { + source: this.$refs.menu.$el, + user: this.user + }); } } }); @@ -187,6 +202,10 @@ export default Vue.extend({ padding 16px 16px 16px 154px color var(--text) + > .actions + > .follow + width 200px + > .fields margin-top 16px diff --git a/src/client/app/desktop/views/pages/user/user.integrations.integration.vue b/src/client/app/desktop/views/home/user/user.integrations.integration.vue index 4791226881..4791226881 100644 --- a/src/client/app/desktop/views/pages/user/user.integrations.integration.vue +++ b/src/client/app/desktop/views/home/user/user.integrations.integration.vue diff --git a/src/client/app/desktop/views/pages/user/user.integrations.vue b/src/client/app/desktop/views/home/user/user.integrations.vue index d796ff9321..d796ff9321 100644 --- a/src/client/app/desktop/views/pages/user/user.integrations.vue +++ b/src/client/app/desktop/views/home/user/user.integrations.vue diff --git a/src/client/app/desktop/views/pages/user/user.photos.vue b/src/client/app/desktop/views/home/user/user.photos.vue index 13645b9314..005961aaa3 100644 --- a/src/client/app/desktop/views/pages/user/user.photos.vue +++ b/src/client/app/desktop/views/home/user/user.photos.vue @@ -87,7 +87,7 @@ export default Vue.extend({ > .img flex 1 1 33% width 33% - height 80px + height 120px background-position center center background-size cover background-clip content-box diff --git a/src/client/app/desktop/views/pages/user/user.timeline.vue b/src/client/app/desktop/views/home/user/user.timeline.vue index 0571ce76f1..0571ce76f1 100644 --- a/src/client/app/desktop/views/pages/user/user.timeline.vue +++ b/src/client/app/desktop/views/home/user/user.timeline.vue diff --git a/src/client/app/desktop/views/home/user/user.vue b/src/client/app/desktop/views/home/user/user.vue new file mode 100644 index 0000000000..32b1dc2e45 --- /dev/null +++ b/src/client/app/desktop/views/home/user/user.vue @@ -0,0 +1,109 @@ +<template> +<div class="xygkxeaeontfaokvqmiblezmhvhostak" v-if="!fetching"> + <div class="is-suspended" v-if="user.isSuspended"><fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}</div> + <div class="is-remote" v-if="user.host != null"><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a></div> + <div class="main"> + <x-header :user="user"/> + <mk-note-detail v-for="n in user.pinnedNotes" :key="n.id" :note="n" :compact="true"/> + <x-integrations :user="user"/> + <!--<mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/>--> + <div class="activity"> + <mk-widget-container :show-header="true" :naked="false"> + <template slot="header"><fa icon="chart-bar"/>{{ $t('activity') }}</template> + <x-activity :user="user" :limit="35" style="padding: 16px;"/> + </mk-widget-container> + </div> + <x-photos :user="user"/> + <x-friends :user="user"/> + <x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> + <x-timeline class="timeline" ref="tl" :user="user"/> + </div> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import i18n from '../../../../i18n'; +import parseAcct from '../../../../../../misc/acct/parse'; +import Progress from '../../../../common/scripts/loading'; +import XHeader from './user.header.vue'; +import XTimeline from './user.timeline.vue'; +import XPhotos from './user.photos.vue'; +import XFollowersYouKnow from './user.followers-you-know.vue'; +import XFriends from './user.friends.vue'; +import XIntegrations from './user.integrations.vue'; +import XActivity from '../../../../common/views/components/activity.vue'; + +export default Vue.extend({ + i18n: i18n(), + components: { + XHeader, + XTimeline, + XPhotos, + XFollowersYouKnow, + XFriends, + XIntegrations, + XActivity + }, + data() { + return { + fetching: true, + user: null + }; + }, + watch: { + $route: 'fetch' + }, + created() { + this.fetch(); + }, + methods: { + fetch() { + this.fetching = true; + Progress.start(); + this.$root.api('users/show', parseAcct(this.$route.params.user)).then(user => { + this.user = user; + this.fetching = false; + Progress.done(); + }); + }, + + warp(date) { + (this.$refs.tl as any).warp(date); + } + } +}); +</script> + +<style lang="stylus" scoped> +.xygkxeaeontfaokvqmiblezmhvhostak + width 100% + margin 0 auto + + > .is-suspended + > .is-remote + margin-bottom 16px + padding 14px 16px + font-size 14px + box-shadow var(--shadow) + border-radius var(--round) + + &.is-suspended + color var(--suspendedInfoFg) + background var(--suspendedInfoBg) + + &.is-remote + color var(--remoteInfoFg) + background var(--remoteInfoBg) + + > a + font-weight bold + + > .main + > * + margin-bottom 16px + + > .timeline + box-shadow var(--shadow) + +</style> diff --git a/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue b/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue deleted file mode 100644 index b2a6cd5837..0000000000 --- a/src/client/app/desktop/views/pages/deck/deck.hashtag-column.vue +++ /dev/null @@ -1,112 +0,0 @@ -<template> -<x-column> - <span slot="header"> - <fa icon="hashtag"/><span>{{ tag }}</span> - </span> - - <div class="xroyrflcmhhtmlwmyiwpfqiirqokfueb"> - <div ref="chart" class="chart"></div> - <x-hashtag-tl :tag-tl="tagTl" class="tl"/> - </div> -</x-column> -</template> - -<script lang="ts"> -import Vue from 'vue'; -import XColumn from './deck.column.vue'; -import XHashtagTl from './deck.hashtag-tl.vue'; -import ApexCharts from 'apexcharts'; - -export default Vue.extend({ - components: { - XColumn, - XHashtagTl - }, - - props: { - tag: { - type: String, - required: true - } - }, - - computed: { - tagTl(): any { - return { - query: [[this.tag]] - }; - } - }, - - mounted() { - this.$root.api('charts/hashtag', { - tag: this.tag, - span: 'hour', - limit: 24 - }).then(stats => { - const local = []; - const remote = []; - - const now = new Date(); - const y = now.getFullYear(); - const m = now.getMonth(); - const d = now.getDate(); - const h = now.getHours(); - - for (let i = 0; i < 24; i++) { - const x = new Date(y, m, d, h - i); - local.push([x, stats.local.count[i]]); - remote.push([x, stats.remote.count[i]]); - } - - const chart = new ApexCharts(this.$refs.chart, { - chart: { - type: 'area', - height: 70, - sparkline: { - enabled: true - }, - }, - grid: { - clipMarkers: false, - padding: { - top: 16, - right: 16, - bottom: 16, - left: 16 - } - }, - stroke: { - curve: 'straight', - width: 2 - }, - series: [{ - name: 'Local', - data: local - }, { - name: 'Remote', - data: remote - }], - xaxis: { - type: 'datetime', - } - }); - - chart.render(); - }); - } -}); -</script> - -<style lang="stylus" scoped> -.xroyrflcmhhtmlwmyiwpfqiirqokfueb - background var(--deckColumnBg) - - > .chart - margin-bottom 16px - background var(--face) - - > .tl - background var(--face) - -</style> diff --git a/src/client/app/desktop/views/pages/home-customize.vue b/src/client/app/desktop/views/pages/home-customize.vue deleted file mode 100644 index e0460abcd0..0000000000 --- a/src/client/app/desktop/views/pages/home-customize.vue +++ /dev/null @@ -1,3 +0,0 @@ -<template> -<mk-home customize/> -</template> diff --git a/src/client/app/desktop/views/pages/home.vue b/src/client/app/desktop/views/pages/home.vue deleted file mode 100644 index 19e00880af..0000000000 --- a/src/client/app/desktop/views/pages/home.vue +++ /dev/null @@ -1,39 +0,0 @@ -<template> -<mk-ui> - <mk-home :mode="mode" @loaded="loaded" ref="home" v-hotkey.global="keymap"/> -</mk-ui> -</template> - -<script lang="ts"> -import Vue from 'vue'; -import Progress from '../../../common/scripts/loading'; - -export default Vue.extend({ - props: { - mode: { - type: String, - default: 'timeline' - } - }, - computed: { - keymap(): any { - return { - 't': this.focus - }; - } - }, - mounted() { - document.title = this.$root.instanceName; - - Progress.start(); - }, - methods: { - loaded() { - Progress.done(); - }, - focus() { - this.$refs.home.focus(); - } - } -}); -</script> diff --git a/src/client/app/desktop/views/pages/index.vue b/src/client/app/desktop/views/pages/index.vue deleted file mode 100644 index c531e00e4f..0000000000 --- a/src/client/app/desktop/views/pages/index.vue +++ /dev/null @@ -1,25 +0,0 @@ -<template> -<component :is="page"></component> -</template> - -<script lang="ts"> -import Vue from 'vue'; -import Home from './home.vue'; -import Welcome from './welcome.vue'; -import Deck from './deck/deck.vue'; - -export default Vue.extend({ - components: { - Home, - Deck, - Welcome - }, - - computed: { - page(): string { - if (!this.$store.getters.isSignedIn) return 'welcome'; - return this.$store.state.device.deckDefault ? 'deck' : 'home'; - } - } -}); -</script> diff --git a/src/client/app/desktop/views/pages/user/user.profile.vue b/src/client/app/desktop/views/pages/user/user.profile.vue deleted file mode 100644 index 026f84dc8a..0000000000 --- a/src/client/app/desktop/views/pages/user/user.profile.vue +++ /dev/null @@ -1,66 +0,0 @@ -<template> -<div class="profile" v-if="$store.getters.isSignedIn"> - <div class="friend-form" v-if="$store.state.i.id != user.id"> - <mk-follow-button :user="user" block/> - <p class="followed" v-if="user.isFollowed">{{ $t('follows-you') }}</p> - </div> - <div class="action-form"> - <ui-button @click="menu" ref="menu">{{ $t('menu') }}</ui-button> - </div> -</div> -</template> - -<script lang="ts"> -import Vue from 'vue'; -import i18n from '../../../../i18n'; -import XUserMenu from '../../../../common/views/components/user-menu.vue'; - -export default Vue.extend({ - i18n: i18n('desktop/views/pages/user/user.profile.vue'), - props: ['user'], - - methods: { - menu() { - this.$root.new(XUserMenu, { - source: this.$refs.menu.$el, - user: this.user - }); - }, - } -}); -</script> - -<style lang="stylus" scoped> -.profile - background var(--face) - box-shadow var(--shadow) - border-radius var(--round) - - > *:first-child - border-top none !important - - > .friend-form - padding 16px - text-align center - border-bottom solid 1px var(--faceDivider) - - > .followed - margin 12px 0 0 0 - padding 0 - text-align center - line-height 24px - font-size 0.8em - color var(--text) - border-radius 4px - - > .action-form - padding 16px - text-align center - - > * - width 100% - - &:not(:last-child) - margin-bottom 12px - -</style> diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue deleted file mode 100644 index 19f646927b..0000000000 --- a/src/client/app/desktop/views/pages/user/user.vue +++ /dev/null @@ -1,155 +0,0 @@ -<template> -<mk-ui> - <div class="xygkxeaeontfaokvqmiblezmhvhostak" v-if="!fetching"> - <div class="is-suspended" v-if="user.isSuspended"><fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}</div> - <div class="is-remote" v-if="user.host != null"><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a></div> - <main> - <div class="main"> - <x-header :user="user"/> - <mk-note-detail v-for="n in user.pinnedNotes" :key="n.id" :note="n" :compact="true"/> - <x-timeline class="timeline" ref="tl" :user="user"/> - </div> - <div class="side"> - <div class="instance" v-if="!$store.getters.isSignedIn"><mk-instance/></div> - <x-profile :user="user"/> - <x-integrations :user="user"/> - <mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/> - <mk-activity :user="user"/> - <x-photos :user="user"/> - <x-friends :user="user"/> - <x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> - <div class="nav"><mk-nav/></div> - </div> - </main> - </div> -</mk-ui> -</template> - -<script lang="ts"> -import Vue from 'vue'; -import i18n from '../../../../i18n'; -import parseAcct from '../../../../../../misc/acct/parse'; -import Progress from '../../../../common/scripts/loading'; -import XHeader from './user.header.vue'; -import XTimeline from './user.timeline.vue'; -import XProfile from './user.profile.vue'; -import XPhotos from './user.photos.vue'; -import XFollowersYouKnow from './user.followers-you-know.vue'; -import XFriends from './user.friends.vue'; -import XIntegrations from './user.integrations.vue'; - -export default Vue.extend({ - i18n: i18n(), - components: { - XHeader, - XTimeline, - XProfile, - XPhotos, - XFollowersYouKnow, - XFriends, - XIntegrations - }, - data() { - return { - fetching: true, - user: null - }; - }, - watch: { - $route: 'fetch' - }, - created() { - this.fetch(); - }, - methods: { - fetch() { - this.fetching = true; - Progress.start(); - this.$root.api('users/show', parseAcct(this.$route.params.user)).then(user => { - this.user = user; - this.fetching = false; - Progress.done(); - }); - }, - - warp(date) { - (this.$refs.tl as any).warp(date); - } - } -}); -</script> - -<style lang="stylus" scoped> -.xygkxeaeontfaokvqmiblezmhvhostak - max-width 980px - min-width 720px - padding 16px - margin 0 auto - - > .is-suspended - > .is-remote - margin-bottom 16px - padding 14px 16px - font-size 14px - box-shadow var(--shadow) - border-radius var(--round) - - &.is-suspended - color var(--suspendedInfoFg) - background var(--suspendedInfoBg) - - &.is-remote - color var(--remoteInfoFg) - background var(--remoteInfoBg) - - > a - font-weight bold - - > main - display flex - justify-content center - - > .main - > .side - > *:not(:last-child) - margin-bottom 16px - - > .main - flex 1 - min-width 0 // SEE: http://kudakurage.hatenadiary.com/entry/2016/04/01/232722 - margin-right 16px - - > .timeline - box-shadow var(--shadow) - - > .side - width 275px - flex-shrink 0 - - > p - display block - margin 0 - padding 0 12px - text-align center - font-size 0.8em - color var(--text) - - > .instance - box-shadow var(--shadow) - border-radius var(--round) - - > .nav - padding 16px - font-size 12px - color var(--text) - background var(--face) - box-shadow var(--shadow) - border-radius var(--round) - - a - color var(--text)99 - - i - color var(--text) - -</style> diff --git a/src/client/app/desktop/views/widgets/customize.vue b/src/client/app/desktop/views/widgets/customize.vue new file mode 100644 index 0000000000..eb71910382 --- /dev/null +++ b/src/client/app/desktop/views/widgets/customize.vue @@ -0,0 +1,21 @@ +<template> +<div class="mkw-customize"> + <ui-button @click="customize()">{{ $t('@.customize-home') }}</ui-button> +</div> +</template> + +<script lang="ts"> +import define from '../../../common/define-widget'; +import i18n from '../../../i18n'; + +export default define({ + name: 'customize', +}).extend({ + i18n: i18n(), + methods: { + customize(date) { + location.href = '/?customize'; + } + } +}); +</script> diff --git a/src/client/app/desktop/views/widgets/index.ts b/src/client/app/desktop/views/widgets/index.ts index 7c074080c1..38a661671f 100644 --- a/src/client/app/desktop/views/widgets/index.ts +++ b/src/client/app/desktop/views/widgets/index.ts @@ -9,6 +9,7 @@ import wPolls from './polls.vue'; import wPostForm from './post-form.vue'; import wMessaging from './messaging.vue'; import wProfile from './profile.vue'; +import wCustomize from './customize.vue'; Vue.component('mkw-notifications', wNotifications); Vue.component('mkw-timemachine', wTimemachine); @@ -19,3 +20,4 @@ Vue.component('mkw-polls', wPolls); Vue.component('mkw-post-form', wPostForm); Vue.component('mkw-messaging', wMessaging); Vue.component('mkw-profile', wProfile); +Vue.component('mkw-customize', wCustomize); diff --git a/src/client/app/init.ts b/src/client/app/init.ts index 2f18030f0d..710bef8b65 100644 --- a/src/client/app/init.ts +++ b/src/client/app/init.ts @@ -350,7 +350,7 @@ if (localStorage.getItem('should-refresh') == 'true') { } // MiOSを初期化してコールバックする -export default (callback: (launch: (router: VueRouter) => [Vue, MiOS]) => void, sw = false) => { +export default (callback: (launch: (router: VueRouter) => [Vue, MiOS], os: MiOS) => void, sw = false) => { const os = new MiOS(sw); os.init(() => { @@ -436,11 +436,6 @@ export default (callback: (launch: (router: VueRouter) => [Vue, MiOS]) => void, }); //#endregion - // Navigation hook - router.beforeEach((to, from, next) => { - next(os.store.state.navHook && os.store.state.navHook(to) ? false : undefined); - }); - document.addEventListener('visibilitychange', () => { if (!document.hidden) { os.store.commit('clearBehindNotes'); @@ -507,6 +502,6 @@ export default (callback: (launch: (router: VueRouter) => [Vue, MiOS]) => void, return [app, os] as [Vue, MiOS]; }; - callback(launch); + callback(launch, os); }); }; diff --git a/src/client/app/mobile/views/pages/user/home.vue b/src/client/app/mobile/views/pages/user/home.vue index 09b4c3f265..98b4f44476 100644 --- a/src/client/app/mobile/views/pages/user/home.vue +++ b/src/client/app/mobile/views/pages/user/home.vue @@ -49,7 +49,7 @@ export default Vue.extend({ XPhotos, XFriends, XFollowersYouKnow, - XActivity: () => import('../../components/activity.vue').then(m => m.default) + XActivity: () => import('../../../../common/views/components/activity.vue').then(m => m.default) }, props: ['user'] }); diff --git a/src/client/app/mobile/views/widgets/activity.vue b/src/client/app/mobile/views/widgets/activity.vue index 4dcab8e3b5..08526416cd 100644 --- a/src/client/app/mobile/views/widgets/activity.vue +++ b/src/client/app/mobile/views/widgets/activity.vue @@ -21,7 +21,7 @@ export default define({ }).extend({ i18n: i18n(), components: { - XActivity: () => import('../components/activity.vue').then(m => m.default) + XActivity: () => import('../../../common/views/components/activity.vue').then(m => m.default) }, methods: { func() { diff --git a/src/client/app/store.ts b/src/client/app/store.ts index d0f61f8bc1..a91164c0b5 100644 --- a/src/client/app/store.ts +++ b/src/client/app/store.ts @@ -10,7 +10,6 @@ const defaultSettings = { home: null, mobileHome: [], deck: null, - deckNav: true, keepCw: false, tagTimelines: [], fetchOnScroll: true, @@ -67,8 +66,7 @@ const defaultDeviceSettings = { deckColumnAlign: 'center', deckColumnWidth: 'normal', mobileNotificationPosition: 'bottom', - deckTemporaryColumn: null, - deckDefault: false, + deckMode: false, useOsDefaultEmojis: false, disableShowingAnimatedImages: false }; @@ -82,7 +80,6 @@ export default (os: MiOS) => new Vuex.Store({ i: null, indicate: false, uiHeaderHeight: 0, - navHook: null, behindNotes: [] }, @@ -107,10 +104,6 @@ export default (os: MiOS) => new Vuex.Store({ state.uiHeaderHeight = height; }, - navHook(state, callback) { - state.navHook = callback; - }, - pushBehindNote(state, note) { if (note.userId === state.i.id) return; if (state.behindNotes.some(n => n.id === note.id)) return; |