diff options
Diffstat (limited to 'src/client/components/sidebar.vue')
| -rw-r--r-- | src/client/components/sidebar.vue | 272 |
1 files changed, 124 insertions, 148 deletions
diff --git a/src/client/components/sidebar.vue b/src/client/components/sidebar.vue index 77e9af27e5..7548b136ea 100644 --- a/src/client/components/sidebar.vue +++ b/src/client/components/sidebar.vue @@ -4,7 +4,7 @@ <div class="nav-back _modalBg" v-if="showing" @click="showing = false" - @touchstart="showing = false" + @touchstart.passive="showing = false" ></div> </transition> @@ -12,31 +12,31 @@ <nav class="nav" :class="{ iconOnly, hidden }" v-show="showing"> <div> <button class="item _button account" @click="openAccountMenu" v-if="$store.getters.isSignedIn"> - <mk-avatar :user="$store.state.i" class="avatar"/><mk-acct class="text" :user="$store.state.i"/> + <MkAvatar :user="$store.state.i" class="avatar"/><MkAcct class="text" :user="$store.state.i"/> </button> <button class="item _button index active" @click="top()" v-if="$route.name === 'index'"> - <fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span> + <Fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span> </button> <router-link class="item index" active-class="active" to="/" exact v-else> - <fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span> + <Fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span> </router-link> <template v-for="item in menu"> <div v-if="item === '-'" class="divider"></div> - <component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" @click="() => { if (menuDef[item].action) menuDef[item].action() }" :to="menuDef[item].to"> - <fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span> - <i v-if="menuDef[item].indicated"><fa :icon="faCircle"/></i> + <component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to"> + <Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span> + <i v-if="menuDef[item].indicated"><Fa :icon="faCircle"/></i> </component> </template> <div class="divider"></div> <button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)" @click="oepnInstanceMenu"> - <fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span> + <Fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span> </button> <button class="item _button" @click="more"> - <fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span> - <i v-if="otherNavItemIndicated"><fa :icon="faCircle"/></i> + <Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span> + <i v-if="otherNavItemIndicated"><Fa :icon="faCircle"/></i> </button> - <router-link class="item" active-class="active" to="/preferences"> - <fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span> + <router-link class="item" active-class="active" to="/settings"> + <Fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span> </router-link> </div> </nav> @@ -45,13 +45,15 @@ </template> <script lang="ts"> -import Vue from 'vue'; -import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram } from '@fortawesome/free-solid-svg-icons'; +import { defineComponent } from 'vue'; +import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram, faStream } from '@fortawesome/free-solid-svg-icons'; import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons'; -import { host, instanceName } from '../config'; -import { search } from '../scripts/search'; +import { host, instanceName } from '@/config'; +import { search } from '@/scripts/search'; +import * as os from '@/os'; +import { sidebarDef } from '@/sidebar'; -export default Vue.extend({ +export default defineComponent({ data() { return { host: host, @@ -59,9 +61,7 @@ export default Vue.extend({ searching: false, accounts: [], connection: null, - menuDef: this.$store.getters.nav({ - search: this.search - }), + menuDef: sidebarDef, iconOnly: false, hidden: false, faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram @@ -127,7 +127,7 @@ export default Vue.extend({ search() { if (this.searching) return; - this.$root.dialog({ + os.dialog({ title: this.$t('search'), input: true }).then(async ({ canceled, result: query }) => { @@ -141,7 +141,7 @@ export default Vue.extend({ }, async openAccountMenu(ev) { - const accounts = (await this.$root.api('users/show', { userIds: this.$store.state.device.accounts.map(x => x.id) })).filter(x => x.id !== this.$store.state.i.id); + const accounts = (await os.api('users/show', { userIds: this.$store.state.device.accounts.map(x => x.id) })).filter(x => x.id !== this.$store.state.i.id); const accountItems = accounts.map(account => ({ type: 'user', @@ -149,96 +149,80 @@ export default Vue.extend({ action: () => { this.switchAccount(account); } })); - this.$root.menu({ - items: [...[{ - type: 'link', - text: this.$t('profile'), - to: `/@${ this.$store.state.i.username }`, - avatar: this.$store.state.i, - }, { - type: 'link', - text: this.$t('accountSettings'), - to: '/my/settings', - icon: faCog, - }, null, ...accountItems, { - icon: faPlus, - text: this.$t('addAcount'), - action: () => { - this.$root.menu({ - items: [{ - text: this.$t('existingAcount'), - action: () => { this.addAcount(); }, - }, { - text: this.$t('createAccount'), - action: () => { this.createAccount(); }, - }], - align: 'left', - fixed: true, - width: 240, - source: ev.currentTarget || ev.target, - }); - }, - }]], - align: 'left', - fixed: true, - width: 240, - source: ev.currentTarget || ev.target, + os.modalMenu([...[{ + type: 'link', + text: this.$t('profile'), + to: `/@${ this.$store.state.i.username }`, + avatar: this.$store.state.i, + }, null, ...accountItems, { + icon: faPlus, + text: this.$t('addAcount'), + action: () => { + os.modalMenu([{ + text: this.$t('existingAcount'), + action: () => { this.addAcount(); }, + }, { + text: this.$t('createAccount'), + action: () => { this.createAccount(); }, + }], ev.currentTarget || ev.target); + }, + }]], ev.currentTarget || ev.target, { + align: 'left' }); }, oepnInstanceMenu(ev) { - this.$root.menu({ - items: [{ - type: 'link', - text: this.$t('dashboard'), - to: '/instance', - icon: faTachometerAlt, - }, null, { - type: 'link', - text: this.$t('settings'), - to: '/instance/settings', - icon: faCog, - }, { - type: 'link', - text: this.$t('customEmojis'), - to: '/instance/emojis', - icon: faLaugh, - }, { - type: 'link', - text: this.$t('users'), - to: '/instance/users', - icon: faUsers, - }, { - type: 'link', - text: this.$t('files'), - to: '/instance/files', - icon: faCloud, - }, { - type: 'link', - text: this.$t('jobQueue'), - to: '/instance/queue', - icon: faExchangeAlt, - }, { - type: 'link', - text: this.$t('federation'), - to: '/instance/federation', - icon: faGlobe, - }, { - type: 'link', - text: this.$t('relays'), - to: '/instance/relays', - icon: faProjectDiagram, - }, { - type: 'link', - text: this.$t('announcements'), - to: '/instance/announcements', - icon: faBroadcastTower, - }], - align: 'left', - fixed: true, - width: 200, - source: ev.currentTarget || ev.target, - }); + os.modalMenu([{ + type: 'link', + text: this.$t('dashboard'), + to: '/instance', + icon: faTachometerAlt, + }, null, this.$store.state.i.isAdmin ? { + type: 'link', + text: this.$t('settings'), + to: '/instance/settings', + icon: faCog, + } : undefined, { + type: 'link', + text: this.$t('customEmojis'), + to: '/instance/emojis', + icon: faLaugh, + }, { + type: 'link', + text: this.$t('users'), + to: '/instance/users', + icon: faUsers, + }, { + type: 'link', + text: this.$t('files'), + to: '/instance/files', + icon: faCloud, + }, { + type: 'link', + text: this.$t('jobQueue'), + to: '/instance/queue', + icon: faExchangeAlt, + }, { + type: 'link', + text: this.$t('federation'), + to: '/instance/federation', + icon: faGlobe, + }, { + type: 'link', + text: this.$t('relays'), + to: '/instance/relays', + icon: faProjectDiagram, + }, { + type: 'link', + text: this.$t('announcements'), + to: '/instance/announcements', + icon: faBroadcastTower, + }, { + type: 'link', + text: this.$t('logs'), + to: '/instance/logs', + icon: faStream, + }], ev.currentTarget || ev.target); }, more(ev) { @@ -250,45 +234,40 @@ export default Vue.extend({ action: def.action, indicate: def.indicated, })); - this.$root.menu({ - items: [...items, null, { - type: 'link', - text: this.$t('help'), - to: '/docs', - icon: faQuestionCircle, - }, { - type: 'link', - text: this.$t('aboutX', { x: instanceName || host }), - to: '/about', - icon: faInfoCircle, - }, { - type: 'link', - text: this.$t('aboutMisskey'), - to: '/about-misskey', - icon: faInfoCircle, - }], - align: 'left', - fixed: true, - width: 200, - source: ev.currentTarget || ev.target, - }); + os.modalMenu([...items, null, { + type: 'link', + text: this.$t('help'), + to: '/docs', + icon: faQuestionCircle, + }, { + type: 'link', + text: this.$t('aboutX', { x: instanceName || host }), + to: '/about', + icon: faInfoCircle, + }, { + type: 'link', + text: this.$t('aboutMisskey'), + to: '/about-misskey', + icon: faInfoCircle, + }], ev.currentTarget || ev.target); }, async addAcount() { - this.$root.new(await import('./signin-dialog.vue').then(m => m.default)).$once('login', res => { - this.$store.dispatch('addAcount', res); - this.$root.dialog({ - type: 'success', - iconOnly: true, autoClose: true - }); - }); + os.popup(await import('./signin-dialog.vue'), {}, { + done: res => { + this.$store.dispatch('addAcount', res); + os.success(); + }, + }, 'closed'); }, async createAccount() { - this.$root.new(await import('./signup-dialog.vue').then(m => m.default)).$once('signup', res => { - this.$store.dispatch('addAcount', res); - this.switchAccountWithToken(res.i); - }); + os.popup(await import('./signup-dialog.vue'), {}, { + done: res => { + this.$store.dispatch('addAcount', res); + this.switchAccountWithToken(res.i); + }, + }, 'closed'); }, async switchAccount(account: any) { @@ -297,12 +276,9 @@ export default Vue.extend({ }, switchAccountWithToken(token: string) { - this.$root.dialog({ - type: 'waiting', - iconOnly: true - }); + os.waiting(); - this.$root.api('i', {}, token).then((i: any) => { + os.api('i', {}, token).then((i: any) => { this.$store.dispatch('switchAccount', { ...i, token: token @@ -324,7 +300,7 @@ export default Vue.extend({ transform: translateX(0); transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1); } -.nav-enter, +.nav-enter-from, .nav-leave-active { opacity: 0; transform: translateX(-240px); @@ -335,7 +311,7 @@ export default Vue.extend({ opacity: 1; transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1); } -.nav-back-enter, +.nav-back-enter-from, .nav-back-leave-active { opacity: 0; } |