feat(client): blur effect for modal

This commit is contained in:
syuilo 2020-07-12 18:14:59 +09:00
parent 426c2fa5d1
commit aae9bc4cf4
11 changed files with 64 additions and 76 deletions

View file

@ -528,6 +528,7 @@ plugins: "プラグイン"
pluginInstallWarn: "信頼できないプラグインはインストールしないでください。" pluginInstallWarn: "信頼できないプラグインはインストールしないでください。"
deck: "デッキ" deck: "デッキ"
undeck: "デッキ解除" undeck: "デッキ解除"
useBlurEffectForModal: "モーダルにぼかし効果を使用"
_theme: _theme:
explore: "テーマを探す" explore: "テーマを探す"

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="mk-dialog" :class="{ iconOnly }"> <div class="mk-dialog" :class="{ iconOnly }">
<transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear> <transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear>
<div class="bg" ref="bg" @click="onBgClick" v-if="show"></div> <div class="bg _modalBg" ref="bg" @click="onBgClick" v-if="show"></div>
</transition> </transition>
<transition :name="$store.state.device.animation ? 'dialog' : ''" appear @after-leave="() => { destroyDom(); }"> <transition :name="$store.state.device.animation ? 'dialog' : ''" appear @after-leave="() => { destroyDom(); }">
<div class="main" ref="main" v-if="show"> <div class="main" ref="main" v-if="show">
@ -245,16 +245,6 @@ export default Vue.extend({
width: initial; width: initial;
} }
> .bg {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
}
> .main { > .main {
display: block; display: block;
position: fixed; position: fixed;

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="mk-modal" v-hotkey.global="keymap"> <div class="mk-modal" v-hotkey.global="keymap">
<transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear> <transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear>
<div class="bg" ref="bg" v-if="show" @click="canClose ? close() : () => {}"></div> <div class="bg _modalBg" ref="bg" v-if="show" @click="canClose ? close() : () => {}"></div>
</transition> </transition>
<transition :name="$store.state.device.animation ? 'modal' : ''" appear @after-leave="() => { $emit('closed'); destroyDom(); }"> <transition :name="$store.state.device.animation ? 'modal' : ''" appear @after-leave="() => { $emit('closed'); destroyDom(); }">
<div class="content" ref="content" v-if="show" @click.self="canClose ? close() : () => {}"><slot></slot></div> <div class="content" ref="content" v-if="show" @click.self="canClose ? close() : () => {}"><slot></slot></div>
@ -60,13 +60,7 @@ export default Vue.extend({
.mk-modal { .mk-modal {
> .bg { > .bg {
position: fixed;
top: 0;
left: 0;
z-index: 10000; z-index: 10000;
width: 100%;
height: 100%;
background: var(--modalBg)
} }
> .content { > .content {

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="mk-popup" v-hotkey.global="keymap"> <div class="mk-popup" v-hotkey.global="keymap">
<transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear> <transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear>
<div class="bg" ref="bg" @click="close()" v-if="show"></div> <div class="bg _modalBg" ref="bg" @click="close()" v-if="show"></div>
</transition> </transition>
<transition :name="$store.state.device.animation ? 'popup' : ''" appear @after-leave="() => { $emit('closed'); destroyDom(); }"> <transition :name="$store.state.device.animation ? 'popup' : ''" appear @after-leave="() => { $emit('closed'); destroyDom(); }">
<div class="content" :class="{ fixed }" ref="content" v-if="show" :style="{ width: width ? width + 'px' : 'auto' }"><slot></slot></div> <div class="content" :class="{ fixed }" ref="content" v-if="show" :style="{ width: width ? width + 'px' : 'auto' }"><slot></slot></div>
@ -128,13 +128,7 @@ export default Vue.extend({
.mk-popup { .mk-popup {
> .bg { > .bg {
position: fixed;
top: 0;
left: 0;
z-index: 10000; z-index: 10000;
width: 100%;
height: 100%;
background: var(--modalBg)
} }
> .content { > .content {

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="ulveipglmagnxfgvitaxyszerjwiqmwl"> <div class="ulveipgl">
<transition :name="$store.state.device.animation ? 'form-fade' : ''" appear @after-leave="$emit('closed');"> <transition :name="$store.state.device.animation ? 'form-fade' : ''" appear @after-leave="$emit('closed');">
<div class="bg" ref="bg" v-if="show" @click="close()"></div> <div class="bg _modalBg" ref="bg" v-if="show" @click="close()"></div>
</transition> </transition>
<div class="main" ref="main" @click.self="close()" @keydown="onKeydown"> <div class="main" ref="main" @click.self="close()" @keydown="onKeydown">
<transition :name="$store.state.device.animation ? 'form' : ''" appear <transition :name="$store.state.device.animation ? 'form' : ''" appear
@ -119,16 +119,9 @@ export default Vue.extend({
opacity: 0; opacity: 0;
} }
.ulveipglmagnxfgvitaxyszerjwiqmwl { .ulveipgl {
> .bg { > .bg {
display: block;
position: fixed;
z-index: 10000; z-index: 10000;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(#000, 0.7);
} }
> .main { > .main {

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="mvcprjjd"> <div class="mvcprjjd">
<transition name="nav-back"> <transition name="nav-back">
<div class="nav-back" <div class="nav-back _modalBg"
v-if="showing" v-if="showing"
@click="showing = false" @click="showing = false"
@touchstart="showing = false" @touchstart="showing = false"
@ -320,13 +320,7 @@ export default Vue.extend({
$nav-hide-threshold: 650px; // TODO: $nav-hide-threshold: 650px; // TODO:
> .nav-back { > .nav-back {
position: fixed;
top: 0;
left: 0;
z-index: 1001; z-index: 1001;
width: 100%;
height: 100%;
background: var(--modalBg);
} }
> .nav { > .nav {

View file

@ -106,36 +106,17 @@ document.body.innerHTML = '<div id="app"></div>';
const store = createStore(); const store = createStore();
window.addEventListener('storage', e => {
if (e.key === 'vuex') {
store.replaceState(JSON.parse(localStorage['vuex']));
} else if (e.key === 'i') {
location.reload();
}
}, false);
const os = new MiOS(store); const os = new MiOS(store);
os.init(async () => { os.init(async () => {
window.addEventListener('storage', e => {
if (e.key === 'vuex') {
store.replaceState(JSON.parse(localStorage['vuex']));
} else if (e.key === 'i') {
location.reload();
}
}, false);
store.watch(state => state.device.darkMode, darkMode => {
import('./scripts/theme').then(({ builtinThemes }) => {
const themes = builtinThemes.concat(store.state.device.themes);
applyTheme(themes.find(x => x.id === (darkMode ? store.state.device.darkTheme : store.state.device.lightTheme)));
});
});
//#region Sync dark mode
if (store.state.device.syncDeviceDarkMode) {
store.commit('device/set', { key: 'darkMode', value: isDeviceDarkmode() });
}
window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => {
if (store.state.device.syncDeviceDarkMode) {
store.commit('device/set', { key: 'darkMode', value: mql.matches });
}
});
//#endregion
//#region Fetch locale data //#region Fetch locale data
const i18n = new VueI18n(); const i18n = new VueI18n();
@ -148,13 +129,6 @@ os.init(async () => {
}); });
//#endregion //#endregion
if ('Notification' in window && store.getters.isSignedIn) {
// 許可を得ていなかったらリクエスト
if (Notification.permission === 'default') {
Notification.requestPermission();
}
}
const app = new Vue({ const app = new Vue({
store: store, store: store,
i18n, i18n,
@ -228,6 +202,29 @@ os.init(async () => {
// マウント // マウント
app.$mount('#app'); app.$mount('#app');
store.watch(state => state.device.darkMode, darkMode => {
import('./scripts/theme').then(({ builtinThemes }) => {
const themes = builtinThemes.concat(store.state.device.themes);
applyTheme(themes.find(x => x.id === (darkMode ? store.state.device.darkTheme : store.state.device.lightTheme)));
});
});
//#region Sync dark mode
if (store.state.device.syncDeviceDarkMode) {
store.commit('device/set', { key: 'darkMode', value: isDeviceDarkmode() });
}
window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => {
if (store.state.device.syncDeviceDarkMode) {
store.commit('device/set', { key: 'darkMode', value: mql.matches });
}
});
//#endregion
store.watch(state => state.device.useBlurEffectForModal, v => {
document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none');
}, { immediate: true });
os.stream.on('emojiAdded', data => { os.stream.on('emojiAdded', data => {
// TODO // TODO
//store.commit('instance/set', ); //store.commit('instance/set', );
@ -263,6 +260,13 @@ os.init(async () => {
} }
if (store.getters.isSignedIn) { if (store.getters.isSignedIn) {
if ('Notification' in window) {
// 許可を得ていなかったらリクエスト
if (Notification.permission === 'default') {
Notification.requestPermission();
}
}
const main = os.stream.useSharedConnection('main'); const main = os.stream.useSharedConnection('main');
// 自分の情報が更新されたとき // 自分の情報が更新されたとき

View file

@ -78,6 +78,7 @@
<mk-switch v-model="imageNewTab">{{ $t('openImageInNewTab') }}</mk-switch> <mk-switch v-model="imageNewTab">{{ $t('openImageInNewTab') }}</mk-switch>
<mk-switch v-model="disableAnimatedMfm">{{ $t('disableAnimatedMfm') }}</mk-switch> <mk-switch v-model="disableAnimatedMfm">{{ $t('disableAnimatedMfm') }}</mk-switch>
<mk-switch v-model="reduceAnimation">{{ $t('reduceUiAnimation') }}</mk-switch> <mk-switch v-model="reduceAnimation">{{ $t('reduceUiAnimation') }}</mk-switch>
<mk-switch v-model="useBlurEffectForModal">{{ $t('useBlurEffectForModal') }}</mk-switch>
<mk-switch v-model="useOsNativeEmojis"> <mk-switch v-model="useOsNativeEmojis">
{{ $t('useOsNativeEmojis') }} {{ $t('useOsNativeEmojis') }}
<template #desc><mfm text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></template> <template #desc><mfm text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></template>
@ -178,6 +179,11 @@ export default Vue.extend({
set(value) { this.$store.commit('device/set', { key: 'animation', value: !value }); } set(value) { this.$store.commit('device/set', { key: 'animation', value: !value }); }
}, },
useBlurEffectForModal: {
get() { return this.$store.state.device.useBlurEffectForModal; },
set(value) { this.$store.commit('device/set', { key: 'useBlurEffectForModal', value: value }); }
},
disableAnimatedMfm: { disableAnimatedMfm: {
get() { return !this.$store.state.device.animatedMfm; }, get() { return !this.$store.state.device.animatedMfm; },
set(value) { this.$store.commit('device/set', { key: 'animatedMfm', value: !value }); } set(value) { this.$store.commit('device/set', { key: 'animatedMfm', value: !value }); }

View file

@ -68,6 +68,7 @@ export const defaultDeviceSettings = {
disablePagesScript: true, disablePagesScript: true,
enableInfiniteScroll: true, enableInfiniteScroll: true,
fixedWidgetsPosition: false, fixedWidgetsPosition: false,
useBlurEffectForModal: true,
roomGraphicsQuality: 'medium', roomGraphicsQuality: 'medium',
roomUseOrthographicCamera: true, roomUseOrthographicCamera: true,
deckColumnAlign: 'left', deckColumnAlign: 'left',

View file

@ -197,6 +197,16 @@ hr {
} }
} }
._modalBg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--modalBg);
backdrop-filter: var(--modalBgFilter);
}
._button { ._button {
appearance: none; appearance: none;
padding: 0; padding: 0;

View file

@ -12,6 +12,7 @@
panelHeaderBg: '@panel', panelHeaderBg: '@panel',
panelHeaderDivider: '@divider', panelHeaderDivider: '@divider',
panelBorder: '@divider', panelBorder: '@divider',
modalBg: 'rgba(255, 255, 255, 0.1)',
messageBg: '#1d1d1d', messageBg: '#1d1d1d',
deckColumnBorder: '@divider', deckColumnBorder: '@divider',
}, },