mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-14 05:57:32 -07:00
Resolve #2900
This commit is contained in:
parent
3bdc97b242
commit
dde809825d
5 changed files with 277 additions and 3 deletions
|
@ -883,6 +883,11 @@ desktop/views/components/settings.vue:
|
|||
task-manager: "タスクマネージャ"
|
||||
third-parties: "サードパーティ"
|
||||
|
||||
navbar-position: "ナビゲーションバーの位置"
|
||||
navbar-position-top: "上"
|
||||
navbar-position-left: "左"
|
||||
navbar-position-right: "右"
|
||||
|
||||
desktop/views/components/settings.2fa.vue:
|
||||
intro: "二段階認証を設定すると、サインイン時にパスワードだけでなく、予め登録しておいた物理的なデバイス(例えばあなたのスマートフォンなど)も必要になり、よりセキュリティが向上します。"
|
||||
detail: "詳細..."
|
||||
|
|
|
@ -88,6 +88,13 @@
|
|||
<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
|
||||
<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
|
||||
<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
|
||||
|
||||
<section>
|
||||
<header>%i18n:@navbar-position%</header>
|
||||
<ui-radio v-model="navbar" value="top">%i18n:@navbar-position-top%</ui-radio>
|
||||
<ui-radio v-model="navbar" value="left">%i18n:@navbar-position-left%</ui-radio>
|
||||
<ui-radio v-model="navbar" value="right">%i18n:@navbar-position-right%</ui-radio>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
|
@ -293,6 +300,11 @@ export default Vue.extend({
|
|||
set(value) { this.$store.commit('device/set', { key: 'darkmode', value }); }
|
||||
},
|
||||
|
||||
navbar: {
|
||||
get() { return this.$store.state.device.navbar; },
|
||||
set(value) { this.$store.commit('device/set', { key: 'navbar', value }); }
|
||||
},
|
||||
|
||||
enableSounds: {
|
||||
get() { return this.$store.state.device.enableSounds; },
|
||||
set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); }
|
||||
|
|
237
src/client/app/desktop/views/components/ui.sidebar.vue
Normal file
237
src/client/app/desktop/views/components/ui.sidebar.vue
Normal file
|
@ -0,0 +1,237 @@
|
|||
<template>
|
||||
<div class="header" :class="$store.state.device.navbar">
|
||||
<div class="post">
|
||||
<button @click="post" title="%i18n:@post%">%fa:pencil-alt%</button>
|
||||
</div>
|
||||
|
||||
<div class="nav" v-if="$store.getters.isSignedIn">
|
||||
<div class="home" :class="{ active: $route.name == 'index' }" @click="goToTop">
|
||||
<router-link to="/">%fa:home%</router-link>
|
||||
</div>
|
||||
<div class="deck" :class="{ active: $route.name == 'deck' }" @click="goToTop">
|
||||
<router-link to="/deck">%fa:columns%</router-link>
|
||||
</div>
|
||||
<div class="messaging">
|
||||
<a @click="messaging">%fa:comments%<template v-if="hasUnreadMessagingMessage">%fa:circle%</template></a>
|
||||
</div>
|
||||
<div class="game">
|
||||
<a @click="game">%fa:gamepad%<template v-if="hasGameInvitations">%fa:circle%</template></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav bottom" v-if="$store.getters.isSignedIn">
|
||||
<div>
|
||||
<a @click="drive">%fa:cloud%</a>
|
||||
</div>
|
||||
<div>
|
||||
<router-link to="/i/favorites">%fa:star%</router-link>
|
||||
</div>
|
||||
<div v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
|
||||
<a @click="followRequests">%fa:envelope R%<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></a>
|
||||
</div>
|
||||
<div>
|
||||
<a @click="settings">%fa:cog%</a>
|
||||
</div>
|
||||
<div>
|
||||
<a @click="dark"><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template></a>
|
||||
</div>
|
||||
<div class="signout">
|
||||
<a @click="signout">%fa:power-off%</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="account">
|
||||
<router-link :to="`/@${ $store.state.i.username }`">
|
||||
<mk-avatar class="avatar" :user="$store.state.i"/>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import MkUserListsWindow from './user-lists-window.vue';
|
||||
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
|
||||
import MkSettingsWindow from './settings-window.vue';
|
||||
import MkDriveWindow from './drive-window.vue';
|
||||
import MkMessagingWindow from './messaging-window.vue';
|
||||
import MkGameWindow from './game-window.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
hasGameInvitations: false,
|
||||
connection: null
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
hasUnreadMessagingMessage(): boolean {
|
||||
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadMessagingMessage;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection = (this as any).os.stream.useSharedConnection('main');
|
||||
|
||||
this.connection.on('reversiInvited', this.onReversiInvited);
|
||||
this.connection.on('reversi_no_invites', this.onReversiNoInvites);
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection.dispose();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onReversiInvited() {
|
||||
this.hasGameInvitations = true;
|
||||
},
|
||||
|
||||
onReversiNoInvites() {
|
||||
this.hasGameInvitations = false;
|
||||
},
|
||||
|
||||
messaging() {
|
||||
(this as any).os.new(MkMessagingWindow);
|
||||
},
|
||||
|
||||
game() {
|
||||
(this as any).os.new(MkGameWindow);
|
||||
},
|
||||
|
||||
post() {
|
||||
(this as any).apis.post();
|
||||
},
|
||||
|
||||
drive() {
|
||||
(this as any).os.new(MkDriveWindow);
|
||||
},
|
||||
|
||||
list() {
|
||||
const w = (this as any).os.new(MkUserListsWindow);
|
||||
w.$once('choosen', list => {
|
||||
this.$router.push(`i/lists/${ list.id }`);
|
||||
});
|
||||
},
|
||||
|
||||
followRequests() {
|
||||
(this as any).os.new(MkFollowRequestsWindow);
|
||||
},
|
||||
|
||||
settings() {
|
||||
(this as any).os.new(MkSettingsWindow);
|
||||
},
|
||||
|
||||
signout() {
|
||||
(this as any).os.signout();
|
||||
},
|
||||
|
||||
dark() {
|
||||
this.$store.commit('device/set', {
|
||||
key: 'darkmode',
|
||||
value: !this.$store.state.device.darkmode
|
||||
});
|
||||
},
|
||||
|
||||
goToTop() {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.header
|
||||
$width = 68px
|
||||
|
||||
position fixed
|
||||
top 0
|
||||
z-index 1000
|
||||
width $width
|
||||
height 100%
|
||||
background var(--desktopHeaderBg)
|
||||
box-shadow var(--shadow)
|
||||
|
||||
&.left
|
||||
left 0
|
||||
|
||||
&.right
|
||||
right 0
|
||||
|
||||
> .nav
|
||||
> *
|
||||
> *
|
||||
display block
|
||||
width $width
|
||||
line-height 56px
|
||||
text-align center
|
||||
font-size 18px
|
||||
color var(--desktopHeaderFg)
|
||||
|
||||
&:hover
|
||||
color var(--desktopHeaderHoverFg)
|
||||
text-decoration none
|
||||
|
||||
> .nav.bottom
|
||||
position absolute
|
||||
bottom 64px
|
||||
left 0
|
||||
|
||||
> .post
|
||||
width $width
|
||||
height $width
|
||||
padding 10px
|
||||
|
||||
> button
|
||||
display inline-block
|
||||
margin 0
|
||||
padding 0 10px
|
||||
height 100%
|
||||
width 100%
|
||||
font-size 1.2em
|
||||
font-weight normal
|
||||
text-decoration none
|
||||
color var(--primaryForeground)
|
||||
background var(--primary) !important
|
||||
outline none
|
||||
border none
|
||||
border-radius 4px
|
||||
transition background 0.1s ease
|
||||
cursor pointer
|
||||
|
||||
*
|
||||
pointer-events none
|
||||
|
||||
&:hover
|
||||
background var(--primaryLighten10) !important
|
||||
|
||||
&:active
|
||||
background var(--primaryDarken10) !important
|
||||
transition background 0s ease
|
||||
|
||||
> .account
|
||||
position absolute
|
||||
bottom 0
|
||||
left 0
|
||||
width $width
|
||||
height $width
|
||||
padding 12px
|
||||
|
||||
> *
|
||||
display block
|
||||
width 100%
|
||||
height 100%
|
||||
|
||||
> .avatar
|
||||
pointer-events none
|
||||
width 100%
|
||||
height 100%
|
||||
|
||||
</style>
|
|
@ -1,8 +1,9 @@
|
|||
<template>
|
||||
<div class="mk-ui" v-hotkey.global="keymap">
|
||||
<div class="bg" v-if="$store.getters.isSignedIn && $store.state.i.wallpaperUrl" :style="style"></div>
|
||||
<x-header class="header" v-show="!zenMode" ref="header"/>
|
||||
<div class="content">
|
||||
<x-header class="header" v-if="navbar == 'top'" v-show="!zenMode" ref="header"/>
|
||||
<x-sidebar class="sidebar" v-if="navbar != 'top'" ref="sidebar"/>
|
||||
<div class="content" :class="[{ sidebar: navbar != 'top' }, navbar]">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<mk-stream-indicator v-if="$store.getters.isSignedIn"/>
|
||||
|
@ -12,10 +13,12 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XHeader from './ui.header.vue';
|
||||
import XSidebar from './ui.sidebar.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XHeader
|
||||
XHeader,
|
||||
XSidebar
|
||||
},
|
||||
|
||||
data() {
|
||||
|
@ -25,6 +28,10 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
computed: {
|
||||
navbar(): string {
|
||||
return this.$store.state.device.navbar;
|
||||
},
|
||||
|
||||
style(): any {
|
||||
if (!this.$store.getters.isSignedIn || this.$store.state.i.wallpaperUrl == null) return {};
|
||||
return {
|
||||
|
@ -45,6 +52,12 @@ export default Vue.extend({
|
|||
watch: {
|
||||
'$store.state.uiHeaderHeight'() {
|
||||
this.$el.style.paddingTop = this.$store.state.uiHeaderHeight + 'px';
|
||||
},
|
||||
|
||||
navbar() {
|
||||
if (this.navbar != 'top') {
|
||||
this.$store.commit('setUiHeaderHeight', 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -87,4 +100,10 @@ export default Vue.extend({
|
|||
@media (max-width 1000px)
|
||||
display none
|
||||
|
||||
> .content.sidebar.left
|
||||
padding-left 64px
|
||||
|
||||
> .content.sidebar.right
|
||||
padding-right 64px
|
||||
|
||||
</style>
|
||||
|
|
|
@ -56,6 +56,7 @@ const defaultDeviceSettings = {
|
|||
loadRawImages: false,
|
||||
alwaysShowNsfw: false,
|
||||
postStyle: 'standard',
|
||||
navbar: 'top',
|
||||
mobileNotificationPosition: 'bottom'
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue