diff options
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/app/boot.js | 22 | ||||
| -rw-r--r-- | src/client/app/common/views/components/games/reversi/reversi.game.vue | 19 | ||||
| -rw-r--r-- | src/client/app/common/views/components/nav.vue | 19 | ||||
| -rw-r--r-- | src/client/app/common/views/components/signup.vue | 74 | ||||
| -rw-r--r-- | src/client/app/common/views/components/url-preview.vue | 20 | ||||
| -rw-r--r-- | src/client/app/config.ts | 2 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/settings.vue | 24 | ||||
| -rw-r--r-- | src/client/app/desktop/views/components/ui.header.account.vue | 11 | ||||
| -rw-r--r-- | src/client/app/desktop/views/pages/admin/admin.dashboard.vue | 14 | ||||
| -rw-r--r-- | src/client/app/mobile/views/components/follow-button.vue | 2 | ||||
| -rw-r--r-- | src/client/app/mobile/views/components/index.ts | 2 | ||||
| -rw-r--r-- | src/client/app/mobile/views/components/mute-button.vue | 79 | ||||
| -rw-r--r-- | src/client/app/mobile/views/components/ui.nav.vue | 5 | ||||
| -rw-r--r-- | src/client/app/mobile/views/pages/settings.vue | 12 | ||||
| -rw-r--r-- | src/client/app/mobile/views/pages/user.vue | 4 | ||||
| -rw-r--r-- | src/client/app/store.ts | 10 |
16 files changed, 232 insertions, 87 deletions
diff --git a/src/client/app/boot.js b/src/client/app/boot.js index 08c3fdeaee..86d48faf1a 100644 --- a/src/client/app/boot.js +++ b/src/client/app/boot.js @@ -32,16 +32,24 @@ //#region Detect app name let app = null; - if (url.pathname == '/docs' || url.pathname.startsWith('/docs/')) app = 'docs'; - if (url.pathname == '/dev' || url.pathname.startsWith('/dev/')) app = 'dev'; - if (url.pathname == '/auth' || url.pathname.startsWith('/auth/')) app = 'auth'; + if (`${url.pathname}/`.startsWith('/docs/')) app = 'docs'; + if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev'; + if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth'; //#endregion //#region Detect the user language - let lang = navigator.language.split('-')[0]; + let lang = null; - // The default language is English - if (!LANGS.includes(lang)) lang = 'en'; + if (LANGS.includes(navigator.language)) { + lang = navigator.language; + } else { + lang = LANGS.find(x => x.split('-')[0] == navigator.language); + + if (lang == null) { + // Fallback + lang = 'en-US'; + } + } if (settings) { if (settings.device.lang) lang = settings.device.lang; @@ -104,7 +112,7 @@ // グローバルにタイマーIDを代入しておく window.mkBootTimer = window.setTimeout(async () => { // Fetch meta - const res = await fetch(API + '/meta', { + const res = await fetch('/api/meta', { method: 'POST', cache: 'no-cache' }); diff --git a/src/client/app/common/views/components/games/reversi/reversi.game.vue b/src/client/app/common/views/components/games/reversi/reversi.game.vue index 389934af97..b432a2308d 100644 --- a/src/client/app/common/views/components/games/reversi/reversi.game.vue +++ b/src/client/app/common/views/components/games/reversi/reversi.game.vue @@ -18,11 +18,11 @@ </div> <div class="board"> - <div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels"> + <div class="labels-x" v-if="this.$store.state.settings.games.reversi.showBoardLabels"> <span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span> </div> <div class="flex"> - <div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels"> + <div class="labels-y" v-if="this.$store.state.settings.games.reversi.showBoardLabels"> <div v-for="i in game.settings.map.length">{{ i }}</div> </div> <div class="cells" :style="cellsStyle"> @@ -30,15 +30,15 @@ :class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }" @click="set(i)" :title="`${String.fromCharCode(65 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`"> - <img v-if="stone === true" :src="blackUser.avatarUrl" alt=""> - <img v-if="stone === false" :src="whiteUser.avatarUrl" alt=""> + <img v-if="stone === true" :src="blackUser.avatarUrl" alt="black" :class="{ contrast: $store.state.settings.games.reversi.useContrastStones }"> + <img v-if="stone === false" :src="whiteUser.avatarUrl" alt="white" :class="{ contrast: $store.state.settings.games.reversi.useContrastStones }"> </div> </div> - <div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels"> + <div class="labels-y" v-if="this.$store.state.settings.games.reversi.showBoardLabels"> <div v-for="i in game.settings.map.length">{{ i }}</div> </div> </div> - <div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels"> + <div class="labels-x" v-if="this.$store.state.settings.games.reversi.showBoardLabels"> <span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span> </div> </div> @@ -421,6 +421,13 @@ root(isDark) width 100% height 100% + &.contrast + &[alt="black"] + filter brightness(.5) + + &[alt="white"] + filter brightness(2) + > .graph display grid grid-template-columns repeat(61, 1fr) diff --git a/src/client/app/common/views/components/nav.vue b/src/client/app/common/views/components/nav.vue index e25dbc78ca..1f745bf69d 100644 --- a/src/client/app/common/views/components/nav.vue +++ b/src/client/app/common/views/components/nav.vue @@ -6,7 +6,7 @@ <i>・</i> <a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a> <i>・</i> - <a :href="devUrl">%i18n:@develop%</a> + <a href="/dev">%i18n:@develop%</a> <i>・</i> <a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on %fa:B twitter%</a> </span> @@ -14,18 +14,21 @@ <script lang="ts"> import Vue from 'vue'; -import { docsUrl, statsUrl, statusUrl, devUrl, repositoryUrl, feedbackUrl, lang } from '../../../config'; +import { lang } from '../../../config'; export default Vue.extend({ data() { return { - aboutUrl: `${docsUrl}/${lang}/about`, - statsUrl, - statusUrl, - devUrl, - repositoryUrl: repositoryUrl || `https://github.com/syuilo/misskey`, - feedbackUrl: feedbackUrl || `https://github.com/syuilo/misskey/issues/new` + aboutUrl: `/docs/${lang}/about`, + repositoryUrl: 'https://github.com/syuilo/misskey', + feedbackUrl: 'https://github.com/syuilo/misskey/issues/new' } + }, + created() { + (this as any).os.getMeta().then(meta => { + if (meta.repositoryUrl) this.repositoryUrl = meta.repositoryUrl; + if (meta.feedbackUrl) this.feedbackUrl = meta.feedbackUrl; + }); } }); </script> diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue index 810b850831..f603b9545c 100644 --- a/src/client/app/common/views/components/signup.vue +++ b/src/client/app/common/views/components/signup.vue @@ -1,41 +1,43 @@ <template> <form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()"> - <ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required> - <span>%i18n:@invitation-code%</span> - <span slot="prefix">%fa:id-card-alt%</span> - <p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p> - </ui-input> - <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername"> - <span>%i18n:@username%</span> - <span slot="prefix">@</span> - <span slot="suffix">@{{ host }}</span> - <p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p> - <p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p> - <p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p> - <p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p> - <p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p> - <p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p> - <p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p> - </ui-input> - <ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true"> - <span>%i18n:@password%</span> - <span slot="prefix">%fa:lock%</span> - <div slot="text"> - <p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p> - <p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p> - <p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p> - </div> - </ui-input> - <ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype"> - <span>%i18n:@password% (%i18n:@retype%)</span> - <span slot="prefix">%fa:lock%</span> - <div slot="text"> - <p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p> - <p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p> - </div> - </ui-input> - <div v-if="meta && meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div> - <ui-button type="submit">%i18n:@create%</ui-button> + <template v-if="meta"> + <ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required> + <span>%i18n:@invitation-code%</span> + <span slot="prefix">%fa:id-card-alt%</span> + <p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p> + </ui-input> + <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername"> + <span>%i18n:@username%</span> + <span slot="prefix">@</span> + <span slot="suffix">@{{ host }}</span> + <p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p> + <p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p> + <p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p> + <p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p> + <p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p> + <p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p> + <p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p> + </ui-input> + <ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true"> + <span>%i18n:@password%</span> + <span slot="prefix">%fa:lock%</span> + <div slot="text"> + <p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p> + <p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p> + <p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p> + </div> + </ui-input> + <ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype"> + <span>%i18n:@password% (%i18n:@retype%)</span> + <span slot="prefix">%fa:lock%</span> + <div slot="text"> + <p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p> + <p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p> + </div> + </ui-input> + <div v-if="meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div> + <ui-button type="submit">%i18n:@create%</ui-button> + </template> </form> </template> diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue index 95dafa8f4c..be69012737 100644 --- a/src/client/app/common/views/components/url-preview.vue +++ b/src/client/app/common/views/components/url-preview.vue @@ -1,5 +1,7 @@ <template> -<iframe v-if="player" :src="player" heigth="250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen /> +<div v-if="player.url" class="player" :style="`padding: ${(player.height || 0) / (player.width || 1) * 100}% 0 0`"> + <iframe :src="player.url" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen /> +</div> <div v-else-if="tweetUrl && detail" class="twitter"> <blockquote ref="tweet" class="twitter-tweet" :data-theme="$store.state.device.darkmode ? 'dark' : null"> <a :href="url"></a> @@ -46,7 +48,11 @@ export default Vue.extend({ thumbnail: null, icon: null, sitename: null, - player: null, + player: { + url: null, + width: null, + height: null + }, tweetUrl: null, misskeyUrl }; @@ -170,9 +176,17 @@ export default Vue.extend({ </script> <style lang="stylus" scoped> -iframe +.twitter + position relative width 100% + > iframe + height 100% + left 0 + position absolute + top 0 + width 100% + root(isDark) > a display block diff --git a/src/client/app/config.ts b/src/client/app/config.ts index 76cd536a49..74b9ea21c8 100644 --- a/src/client/app/config.ts +++ b/src/client/app/config.ts @@ -4,7 +4,6 @@ declare const _THEME_COLOR_: string; declare const _COPYRIGHT_: string; declare const _VERSION_: string; declare const _CODENAME_: string; -declare const _LICENSE_: string; const address = new URL(location.href); @@ -19,4 +18,3 @@ export const themeColor = _THEME_COLOR_; export const copyright = _COPYRIGHT_; export const version = _VERSION_; export const codename = _CODENAME_; -export const license = _LICENSE_; diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue index e249afed85..df131a1a65 100644 --- a/src/client/app/desktop/views/components/settings.vue +++ b/src/client/app/desktop/views/components/settings.vue @@ -56,8 +56,9 @@ <mk-switch v-model="$store.state.settings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%"> <span>%i18n:@show-maps-desc%</span> </mk-switch> - <mk-switch v-model="$store.state.settings.reversiBoardLabels" @change="onChangeReversiBoardLabels" text="%i18n:common.show-reversi-board-labels%"/> <mk-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm" text="%i18n:common.disable-animated-mfm%"/> + <mk-switch v-model="$store.state.settings.games.reversi.showBoardLabels" @change="onChangeReversiBoardLabels" text="%i18n:common.show-reversi-board-labels%"/> + <mk-switch v-model="$store.state.settings.games.reversi.useContrastStones" @change="onChangeUseContrastReversiStones" text="%i18n:common.use-contrast-reversi-stones%"/> </section> <section class="web" v-show="page == 'web'"> @@ -191,12 +192,6 @@ <button class="ui button block" @click="taskmngr">%i18n:@task-manager%</button> </details> </section> - - <section class="other" v-show="page == 'other'"> - <h1>%i18n:@license%</h1> - <div v-html="license"></div> - <a :href="licenseUrl" target="_blank">%i18n:@third-parties%</a> - </section> </div> </div> </template> @@ -211,7 +206,7 @@ import XApi from './settings.api.vue'; import XApps from './settings.apps.vue'; import XSignins from './settings.signins.vue'; import XDrive from './settings.drive.vue'; -import { url, docsUrl, license, lang, langs, version } from '../../../config'; +import { url, langs, version } from '../../../config'; import checkForUpdate from '../../../common/scripts/check-for-update'; import MkTaskManager from './taskmanager.vue'; @@ -230,7 +225,6 @@ export default Vue.extend({ return { page: 'profile', meta: null, - license, version, langs, latestVersion: undefined, @@ -238,10 +232,6 @@ export default Vue.extend({ }; }, computed: { - licenseUrl(): string { - return `${docsUrl}/${lang}/license`; - }, - apiViaStream: { get() { return this.$store.state.device.apiViaStream; }, set(value) { this.$store.commit('device/set', { key: 'apiViaStream', value }); } @@ -387,7 +377,13 @@ export default Vue.extend({ }, onChangeReversiBoardLabels(v) { this.$store.dispatch('settings/set', { - key: 'reversiBoardLabels', + key: 'games.reversi.showBoardLabels', + value: v + }); + }, + onChangeUseContrastReversiStones(v) { + this.$store.dispatch('settings/set', { + key: 'games.reversi.useContrastStones', value: v }); }, 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 4e0fc1cf1a..5e26389d89 100644 --- a/src/client/app/desktop/views/components/ui.header.account.vue +++ b/src/client/app/desktop/views/components/ui.header.account.vue @@ -30,10 +30,8 @@ <li @click="settings"> <p>%fa:cog%<span>%i18n:@settings%</span>%fa:angle-right%</p> </li> - </ul> - <ul> - <li @click="signout"> - <p class="signout">%fa:power-off%<span>%i18n:@signout%</span></p> + <li v-if="$store.state.i.isAdmin"> + <router-link to="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</router-link> </li> </ul> <ul> @@ -41,6 +39,11 @@ <p><span>%i18n:@dark%</span><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template></p> </li> </ul> + <ul> + <li @click="signout"> + <p class="signout">%fa:power-off%<span>%i18n:@signout%</span></p> + </li> + </ul> </div> </transition> </div> diff --git a/src/client/app/desktop/views/pages/admin/admin.dashboard.vue b/src/client/app/desktop/views/pages/admin/admin.dashboard.vue index 3567585cb8..e0d23331b8 100644 --- a/src/client/app/desktop/views/pages/admin/admin.dashboard.vue +++ b/src/client/app/desktop/views/pages/admin/admin.dashboard.vue @@ -11,6 +11,10 @@ <x-cpu-memory :connection="connection"/> </div> <div> + <label> + <input type="checkbox" v-model="disableRegistration" @change="updateMeta"> + <span>disableRegistration</span> + </label> <button class="ui" @click="invite">%i18n:@invite%</button> <p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p> </div> @@ -28,6 +32,7 @@ export default Vue.extend({ data() { return { stats: null, + disableRegistration: false, inviteCode: null, connection: null, connectionId: null @@ -37,6 +42,10 @@ export default Vue.extend({ this.connection = (this as any).os.streams.serverStatsStream.getConnection(); this.connectionId = (this as any).os.streams.serverStatsStream.use(); + (this as any).os.getMeta().then(meta => { + this.disableRegistration = meta.disableRegistration; + }); + (this as any).api('stats').then(stats => { this.stats = stats; }); @@ -49,6 +58,11 @@ export default Vue.extend({ (this as any).api('admin/invite').then(x => { this.inviteCode = x.code; }); + }, + updateMeta() { + (this as any).api('admin/update-meta', { + disableRegistration: this.disableRegistration + }); } } }); diff --git a/src/client/app/mobile/views/components/follow-button.vue b/src/client/app/mobile/views/components/follow-button.vue index b6a52fe1ed..360ee91d4b 100644 --- a/src/client/app/mobile/views/components/follow-button.vue +++ b/src/client/app/mobile/views/components/follow-button.vue @@ -99,7 +99,7 @@ export default Vue.extend({ cursor pointer padding 0 16px margin 0 - min-width 150px + min-width 100px line-height 36px font-size 14px font-weight bold diff --git a/src/client/app/mobile/views/components/index.ts b/src/client/app/mobile/views/components/index.ts index 38c130ecbf..3e830f4e96 100644 --- a/src/client/app/mobile/views/components/index.ts +++ b/src/client/app/mobile/views/components/index.ts @@ -12,6 +12,7 @@ import noteCard from './note-card.vue'; import userCard from './user-card.vue'; import noteDetail from './note-detail.vue'; import followButton from './follow-button.vue'; +import muteButton from './mute-button.vue'; import friendsMaker from './friends-maker.vue'; import notification from './notification.vue'; import notifications from './notifications.vue'; @@ -36,6 +37,7 @@ Vue.component('mk-note-card', noteCard); Vue.component('mk-user-card', userCard); Vue.component('mk-note-detail', noteDetail); Vue.component('mk-follow-button', followButton); +Vue.component('mk-mute-button', muteButton); Vue.component('mk-friends-maker', friendsMaker); Vue.component('mk-notification', notification); Vue.component('mk-notifications', notifications); diff --git a/src/client/app/mobile/views/components/mute-button.vue b/src/client/app/mobile/views/components/mute-button.vue new file mode 100644 index 0000000000..3cb568615d --- /dev/null +++ b/src/client/app/mobile/views/components/mute-button.vue @@ -0,0 +1,79 @@ +<template> +<button + class="mk-mute-button" + :class="{ active: user.isMuted }" + @click="onClick"> + <span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span> + <span v-else>%fa:eye% %i18n:@unmute%</span> +</button> +</template> + +<script lang="ts"> +import Vue from 'vue' +export default Vue.extend({ + props: { + user: { + type: Object, + required: true + } + }, + methods: { + onClick() { + if (!this.user.isMuted) { + this.mute(); + } else { + this.unmute(); + } + }, + mute() { + (this as any).api('mute/create', { userId: this.user.id}) + .then(() => { this.user.isMuted = true }) + .catch(() => { alert('error')}) + }, + unmute() { + (this as any).api('mute/delete', { userId: this.user.id }) + .then(() => { this.user.isMuted = false }) + .catch(() => { alert('error') }) + } + }, +}) +</script> + + +<style lang="stylus" scoped> +@import '~const.styl' + +.mk-mute-button + display block + user-select none + cursor pointer + padding 0 16px + margin 0 + min-width 100px + line-height 36px + font-size 14px + font-weight bold + color $theme-color + background transparent + outline none + border solid 1px $theme-color + border-radius 36px + + &:hover + background rgba($theme-color, 0.1) + + &:active + background rgba($theme-color, 0.2) + + &.active + color $theme-color-foreground + background $theme-color + + &:hover + background lighten($theme-color, 10%) + border-color lighten($theme-color, 10%) + &:active + background darken($theme-color, 10%) + border-color darken($theme-color, 10%) + +</style> diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue index 5257dafd0e..39ea513b76 100644 --- a/src/client/app/mobile/views/components/ui.nav.vue +++ b/src/client/app/mobile/views/components/ui.nav.vue @@ -30,6 +30,7 @@ <ul> <li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li> <li><router-link to="/i/settings" :data-active="$route.name == 'settings'">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li> + <li v-if="$store.getters.isSignedIn && $store.state.i.isAdmin"><router-link to="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</router-link></li> <li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>%i18n:@darkmode%</span></p></li> </ul> </div> @@ -41,7 +42,7 @@ <script lang="ts"> import Vue from 'vue'; -import { docsUrl, lang } from '../../../config'; +import { lang } from '../../../config'; export default Vue.extend({ props: ['isOpen'], @@ -50,7 +51,7 @@ export default Vue.extend({ hasGameInvitation: false, connection: null, connectionId: null, - aboutUrl: `${docsUrl}/${lang}/about` + aboutUrl: `/docs/${lang}/about` }; }, computed: { diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue index 7636a0370a..6b82be099d 100644 --- a/src/client/app/mobile/views/pages/settings.vue +++ b/src/client/app/mobile/views/pages/settings.vue @@ -13,8 +13,9 @@ <ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch> <ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch> <ui-switch v-model="$store.state.settings.iLikeSushi" @change="onChangeILikeSushi">%i18n:common.i-like-sushi%</ui-switch> - <ui-switch v-model="$store.state.settings.reversiBoardLabels" @change="onChangeReversiBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch> <ui-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch> + <ui-switch v-model="$store.state.settings.games.reversi.showBoardLabels" @change="onChangeReversiBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch> + <ui-switch v-model="$store.state.settings.games.reversi.useContrastStones" @change="onChangeUseContrastReversiStones">%i18n:common.use-contrast-reversi-stones%</ui-switch> <div> <div>%i18n:@timeline%</div> @@ -189,7 +190,14 @@ export default Vue.extend({ onChangeReversiBoardLabels(v) { this.$store.dispatch('settings/set', { - key: 'reversiBoardLabels', + key: 'games.reversi.showBoardLabels', + value: v + }); + }, + + onChangeUseContrastReversiStones(v) { + this.$store.dispatch('settings/set', { + key: 'games.reversi.useContrastStones', value: v }); }, diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue index d573538fdd..e72867352f 100644 --- a/src/client/app/mobile/views/pages/user.vue +++ b/src/client/app/mobile/views/pages/user.vue @@ -11,6 +11,7 @@ <a class="avatar"> <img :src="user.avatarUrl" alt="avatar"/> </a> + <mk-mute-button v-if="$store.state.i.id != user.id" :user="user"/> <mk-follow-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> </div> <div class="title"> @@ -184,6 +185,9 @@ root(isDark) border 4px solid $bg border-radius 12px + > .mk-mute-button + float right + > .mk-follow-button float right diff --git a/src/client/app/store.ts b/src/client/app/store.ts index 7e2cc3976b..ba91a11f25 100644 --- a/src/client/app/store.ts +++ b/src/client/app/store.ts @@ -1,5 +1,6 @@ import Vuex from 'vuex'; import createPersistedState from 'vuex-persistedstate'; +import * as nestedProperty from 'nested-property'; import MiOS from './mios'; import { hostname } from './config'; @@ -22,7 +23,12 @@ const defaultSettings = { disableViaMobile: false, memo: null, iLikeSushi: false, - reversiBoardLabels: false + games: { + reversi: { + showBoardLabels: false, + useContrastStones: false + } + } }; const defaultDeviceSettings = { @@ -125,7 +131,7 @@ export default (os: MiOS) => new Vuex.Store({ mutations: { set(state, x: { key: string; value: any }) { - state[x.key] = x.value; + nestedProperty.set(state, x.key, x.value); }, setHome(state, data) { |