This commit is contained in:
kk
2026-07-08 18:00:33 +08:00
commit e66b4a3680
312 changed files with 54718 additions and 0 deletions

388
src/mac/index.vue Normal file
View File

@@ -0,0 +1,388 @@
<template>
<div class="mac_bg"></div>
<div class="desktop">
<div class="top">
<el-dropdown trigger="click">
<div class="logo"><i class="iconfont iconicon_setting"></i></div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<div>{{ userInfo.userName }}</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="switchTheme">退出主题</div>
</el-dropdown-item>
<el-dropdown-item @click="logout">{{ $t('navbar.logOut') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="space"></div>
<div class="status">
<div class="audio">
<i class="iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu-39"></i>
</div>
<div class="datetime">{{ timeString }}</div>
<div class="notification">
<i class="iconfont icon-changyongtubiao-xianxingdaochu-zhuanqu-25"></i>
</div>
</div>
</div>
<div class="body">
<div class="desktop-app">
<template v-for="item in deskTopAppList" :key="item.key">
<div class="app-item" @click="openApp(item)" v-if="!item.hideInDesktop">
<div class="icon" :style="{ backgroundColor: item.iconBgColor, color: item.iconColor }">
<i class="iconfont" :class="item[iconKey]"></i>
</div>
<div class="title">{{ item[labelKey] }}</div>
</div>
</template>
</div>
</div>
<div class="footer">
<div class="space"></div>
<div class="dock">
<template v-for="item in openAppList" :key="item.key">
<div class="item" @click="openApp(item)">
<i
:style="{ backgroundColor: item.iconBgColor, color: item.iconColor }"
class="iconfont"
:class="item[iconKey]"
></i>
<small style="margin-top: 5px; font-size: 10px">{{ item[labelKey] }}</small>
</div>
</template>
</div>
<div class="space"></div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import $Mode from './mode/index';
import index from '@/mixins/index';
import topLock from '@/page/index/top/top-lock.vue';
export default {
mixins: [index],
components: {
topLock,
},
data() {
return {
app: false,
timeString: '',
};
},
computed: {
...mapGetters(['menu', 'tagList', 'tagWel', 'tag', 'userInfo', 'isMacOs']),
labelKey() {
return this.website.menu.label;
},
pathKey() {
return this.website.menu.path;
},
hrefKey() {
return this.website.menu.href;
},
childrenKey() {
return this.website.menu.children;
},
queryKey() {
return this.website.menu.query;
},
iconKey() {
return this.website.menu.icon;
},
menuList() {
let result = [];
const findMenu = list => {
list.forEach(ele => {
if (ele[this.childrenKey] && ele[this.childrenKey].length !== 0) {
findMenu(ele[this.childrenKey]);
} else {
result.push(ele);
}
});
};
findMenu(this.menu);
return result;
},
deskTopAppList() {
return this.menuList;
},
openAppList() {
return [];
},
},
created() {
this.startTimer();
this.$store.dispatch('GetMenu');
},
methods: {
switchTheme() {
this.$store.commit('SET_THEME_NAME', '');
this.$router.push(this.tagWel);
setTimeout(() => location.reload());
},
logout() {
this.$store.commit('SET_THEME_NAME', '');
this.$store.dispatch('LogOut').then(() => {
this.$router.push({ path: '/login' });
setTimeout(() => location.reload());
});
},
startTimer() {
setInterval(() => {
this.timeString = this.$dayjs().format('YYYY年MM月DD日 HH:mm');
}, 1000);
},
openApp(item) {
$Mode({
title: item[this.labelKey],
path: item[this.hrefKey] ? item[this.hrefKey] : item[this.pathKey],
});
},
},
};
</script>
<style>
.top .el-dropdown {
color: white !important;
height: 100% !important;
}
</style>
<style scoped>
.desktop {
display: flex;
flex-direction: column;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: white;
overflow: hidden;
text-shadow: 0px 2px 2px rgba(0, 0, 0, 0.1);
}
.top {
height: 28px;
background-color: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(20px);
display: flex;
flex-direction: row;
font-size: 14px;
align-items: center;
justify-content: center;
padding: 0px 5px;
z-index: 100;
}
.space {
flex-grow: 1;
}
.logo {
height: 100%;
align-items: center;
justify-content: center;
padding: 0px 15px;
cursor: pointer;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.logo .el-select {
position: absolute;
opacity: 0;
}
.logo:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.logo .iconfont {
font-size: 16px;
margin-top: -3px;
}
.menu .item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.status {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 100%;
}
.audio .iconfont,
.notification .iconfont {
font-size: 20px;
}
.datetime,
.audio,
.notification {
cursor: pointer;
padding: 0px 10px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.datetime:hover,
.audio:hover,
.notification:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.body {
flex-grow: 1;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
position: relative;
}
.footer {
position: fixed;
left: 5px;
right: 5px;
bottom: 5px;
justify-content: center;
align-items: center;
display: flex;
flex-direction: row;
z-index: 100;
}
.footer .dock {
background-color: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
border-radius: 10px;
flex-direction: row;
display: flex;
padding: 2px;
}
.dock .item {
padding: 3px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.dock .dot {
width: 3px;
height: 3px;
background: rgba(0, 0, 0, 0.8);
position: absolute;
bottom: 0px;
border-radius: 5px;
display: inline-block;
font-size: 0;
}
.dock .item .iconfont {
cursor: pointer;
border-radius: 20px;
padding: 2px;
display: inline-block;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
height: 30px;
width: 30px;
text-align: center;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.3s, margin 0.3s;
}
.dock .item:hover .iconfont {
transform: scale(2) translateY(-10px);
margin: 0px 15px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.dock .nearby .iconfont {
transform: scale(1.6) translateY(-8px);
margin: 0px 12px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.dock .nearby1 .iconfont {
transform: scale(1.2) translateY(-6px);
margin: 0px 9px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.dock .nearby2 .iconfont {
transform: scale(1.1) translateY(-5px);
margin: 0px 7px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
}
.desktop-app {
position: absolute;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-end;
padding: 20px;
flex-wrap: wrap-reverse;
}
.app-item {
margin: 5px 10px;
padding: 5px;
flex-direction: column;
text-align: center;
text-shadow: 0px 0px 2px rgb(0 0 0 / 50%);
cursor: pointer;
border-radius: 10px;
border: 2px solid transparent;
}
.app-item .icon {
border-radius: 10px;
width: 50px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
}
.app-item .iconfont {
font-size: 36px;
}
.app-item .title {
font-size: 12px;
width: 50px;
margin-top: 5px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.app-item:hover {
border: 2px solid rgba(255, 255, 255, 0.5);
}
</style>

62
src/mac/lock.vue Normal file
View File

@@ -0,0 +1,62 @@
<template>
<div class="mac_bg"></div>
<div class="login animate__animated" :class="{ animate__bounceOut: pass }">
<div class="head">
<img
src="https://bladex.cn/images/logo-small.png"
alt=""
/>
</div>
<div class="message">{{ userInfo.username }}</div>
<div class="form">
<div class="item" style="width: 320px" :class="passwdError ? 'error' : ''">
<input class="password" placeholder="password here..." v-model="passwd" type="password" />
<i class="iconfont el-icon-unlock" @click="handleLogin"></i>
<i class="iconfont icon-tuichu" @click="handleLogout"></i>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
data() {
return {
passwdError: false,
passwd: '',
pass: false,
};
},
computed: {
...mapGetters(['userInfo', 'tag', 'lockPasswd']),
},
methods: {
handleLogout() {
this.$store.dispatch('LogOut').then(() => {
this.$router.push({ path: '/login' });
});
},
handleLogin() {
if (this.passwd !== this.lockPasswd) {
this.passwd = '';
this.passwdError = true;
setTimeout(() => {
this.passwdError = false;
}, 1000);
return;
}
this.pass = true;
setTimeout(() => {
this.$store.commit('CLEAR_LOCK');
this.$router.push({
path: this.tag.value,
});
}, 1000);
},
},
};
</script>
<style lang="scss" scoped>
@use './login.scss';
</style>

134
src/mac/login.scss Normal file
View File

@@ -0,0 +1,134 @@
@keyframes loginErrorAnimation {
0% {
margin-left: -30px;
}
50% {
margin-left: 30px;
}
100% {
margin-left: 0;
}
}
.login {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
margin-top: -100px;
z-index: 99999;
backdrop-filter: blur(20px);
}
.head {
padding: 3px;
background-size: 40% auto;
background-position: center center;
height: 150px;
width: 150px;
border-radius: 100%;
box-sizing: border-box;
box-shadow: 0px 0px 5px 5px rgba(0, 0, 0, 0.1);
margin-top: -50px;
overflow: hidden;
}
.head img {
border-radius: 100%;
width: 100%;
height: 100%;
}
.message {
margin-top: 20px;
font-size: 20px;
text-shadow: 0px 0px 2px 2px rgba(0, 0, 0, 0.3);
color: #eee;
margin-bottom: 50px;
}
.password {
transition: width 0.3s;
}
.password-in {
width: 155px;
}
.login-button {
position: absolute;
top: 5px;
right: -50px;
transition: right 0.3s;
}
.click-enable {
right: 0;
}
.error {
animation: loginErrorAnimation 0.2s ease 3;
}
::-webkit-input-placeholder {
color: #fff;
}
::-moz-placeholder {
color: #fff;
}
:-ms-input-placeholder {
color: #fff;
}
.form {
display: flex;
flex-direction: column;
align-items: center;
}
.item {
position: relative;
width: 280px;
display: flex;
align-items: center;
}
.item input {
color: white;
outline: none;
border: none;
margin: 5px 0;
font-size: 16px;
background-color: rgba(255, 255, 255, 0.3);
padding: 8px 24px;
border-radius: 20px;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
flex: 1;
}
.item .iconfont {
margin-left: 10px;
vertical-align: middle;
display: inline-block;
background-color: rgba(255, 255, 255, 0.3);
font-size: 18px;
border-radius: 100%;
width: 36px;
height: 36px;
text-align: center;
line-height: 36px;
cursor: pointer;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
}
.item .iconfont:hover {
background-color: rgba(255, 255, 255, 0.5);
}

72
src/mac/login.vue Normal file
View File

@@ -0,0 +1,72 @@
<template>
<div class="mac_bg"></div>
<div class="login animate__animated" :class="{ animate__bounceOut: pass }">
<div class="head">
<img
src="https://bladex.cn/images/logo-small.png"
alt=""
/>
</div>
<div class="message">Login Please</div>
<div class="form">
<div class="item" :class="isUserNameError ? 'error' : ''">
<input class="account" placeholder="account here..." v-model="form.username" type="email" />
</div>
<div class="item" :class="isUserPasswordError ? 'error' : ''">
<input
class="password"
placeholder="password here..."
v-model="form.password"
type="password"
/>
<i class="iconfont icon-send" @click="handleLogin"></i>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
data() {
return {
pass: false,
isUserNameError: false,
isUserPasswordError: false,
form: {
username: '',
password: '',
},
};
},
computed: {
...mapGetters(['tagWel']),
},
methods: {
handleLogin() {
if (this.form.username === '') {
this.isUserNameError = true;
setTimeout(() => {
this.isUserNameError = false;
}, 1000);
return;
} else if (this.form.password === '') {
this.isUserPasswordError = true;
setTimeout(() => {
this.isUserPasswordError = false;
}, 1000);
return;
}
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
this.pass = true;
setTimeout(() => {
this.$router.push(this.tagWel);
}, 1000);
});
},
},
};
</script>
<style lang="scss" scoped>
@use './login.scss';
</style>

18
src/mac/mode/index.js Normal file
View File

@@ -0,0 +1,18 @@
import MessageConstructor from './index.vue';
import { createVNode, render } from 'vue';
export default (function () {
return (opts = {}) => {
let options = {
app: opts,
};
const parent = document.createElement('div');
let instance = createVNode(MessageConstructor, options);
instance.props.onDestroy = () => {
render(null, parent);
};
render(instance, parent);
document.body.appendChild(parent.firstElementChild);
return instance;
};
})();

483
src/mac/mode/index.vue Normal file
View File

@@ -0,0 +1,483 @@
<template>
<div
class="moveBg"
v-show="isShow"
@click="handleFocus"
@mousemove="mouseMove"
@mouseup="mouseUp"
@mouseleave.stop="mouseLeave"
:style="{ pointerEvents: isBoxResizing || isBoxMoving ? 'auto' : 'none' }"
>
<div
class="box"
:style="{
left: nowRect.left + 'px',
top: nowRect.top + 'px',
bottom: nowRect.bottom + 'px',
right: nowRect.right + 'px',
}"
:class="getExtBoxClasses()"
>
<div class="box-top">
<div class="box-top-left" @mousedown="resizeMouseDown"></div>
<div class="box-top-center" @mousedown="resizeMouseDown"></div>
<div class="box-top-right" @mousedown="resizeMouseDown"></div>
</div>
<div class="box-center">
<div class="box-center-left" @mousedown="resizeMouseDown"></div>
<div class="box-center-center loader">
<div
class="app-bar"
:style="{ backgroundColor: app.tabbarBgColor }"
@mousedown.stop="positionMouseDown"
v-on:dblclick="appBarDoubleClicked"
>
<div class="controll">
<div class="close" @click.stop="close"></div>
<div
class="full"
:class="app.disableResize ? 'full-disabled' : ''"
@click.stop="switchFullScreen"
></div>
</div>
<div class="title" :style="{ color: app.tabbarTextColor }">{{ app.title }}</div>
</div>
<iframe :src="location + app.path" frameborder="0" class="iframe"></iframe>
</div>
<div class="box-center-right" @mousedown="resizeMouseDown"></div>
</div>
<div class="box-bottom">
<div class="box-bottom-left" @mousedown="resizeMouseDown"></div>
<div class="box-bottom-center" @mousedown="resizeMouseDown"></div>
<div class="box-bottom-right" @mousedown="resizeMouseDown"></div>
</div>
</div>
</div>
</template>
<script>
import { isURL } from 'utils/validate';
import { defineAsyncComponent } from 'vue';
export default {
props: {
app: Object,
onDestroy: Function,
},
data() {
return {
isShow: true,
defaultIndex: 10,
activeIndex: 20,
isBoxMoving: false,
startPosition: { x: 0, y: 0 },
nowRect: {
left: 100,
right: 100,
top: 100,
bottom: 100,
},
startRect: {
left: 0,
right: 0,
top: 0,
bottom: 0,
},
isBoxResizing: false,
moveDirection: false,
isMaxShowing: false,
isFullScreen: false,
};
},
computed: {
location() {
return isURL(this.app.path) ? '' : window.location.origin;
},
},
created() {
if (this.app.width) {
this.nowRect.left = this.nowRect.right = (document.body.clientWidth - this.app.width) / 2;
}
if (this.app.height) {
this.nowRect.bottom = (document.body.clientHeight - this.app.height) / 2 + 50;
this.nowRect.top = (document.body.clientHeight - this.app.height) / 2 - 50;
}
},
methods: {
handleFocus() {
let list = document.getElementsByClassName('moveBg');
if (list.length == 1) return;
let max = 0;
for (let i = 0; i < list.length; i++) {
let ele = list[i];
let box = ele.getElementsByClassName('box')[0].style;
let zIndex = Number(box.zIndex);
if (max < zIndex) {
max = zIndex;
}
}
max = max + 1;
this.$el.getElementsByClassName('box')[0].style.zIndex = max;
},
close() {
this.isShow = false;
this.onDestroy();
},
switchFullScreen() {
if (this.app.disableResize) {
return;
}
this.isFullScreen = !this.isFullScreen;
if (this.isFullScreen) {
this.isMaxShowing = true;
} else {
this.isMaxShowing = false;
}
},
getExtBoxClasses() {
let str = '';
if (!this.isBoxResizing && !this.isBoxMoving) {
str += 'box-animation ';
}
if (this.isMaxShowing) {
str += 'isMaxShowing ';
}
if (this.isFullScreen) {
str += 'isFullScreen ';
}
if (this.app.disableResize) {
str += 'resize-disabled ';
}
if (this.app.isTop) {
str += 'isTop ';
}
return str;
},
appBarDoubleClicked() {
if (this.app.disableResize) {
return;
}
this.isMaxShowing = !this.isMaxShowing;
if (!this.isMaxShowing) {
this.isFullScreen = false;
}
},
positionMouseDown(e) {
if (this.isFullScreen || this.isMaxShowing) {
return;
}
this.startRect = {
left: this.nowRect.left,
right: this.nowRect.right,
top: this.nowRect.top,
bottom: this.nowRect.bottom,
};
this.startPosition.x = e.clientX;
this.startPosition.y = e.clientY;
this.isBoxMoving = true;
},
mouseUp() {
this.isBoxMoving = false;
this.isBoxResizing = false;
this.moveDirection = false;
},
mouseLeave() {
this.isBoxMoving = false;
this.isBoxResizing = false;
this.moveDirection = false;
},
mouseMove(e) {
if (this.isBoxResizing) {
this.isFullScreen = false;
this.isMaxShowing = false;
switch (this.moveDirection) {
case 'box-top-left':
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y);
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x);
break;
case 'box-top-center':
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y);
break;
case 'box-top-right':
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y);
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x);
break;
case 'box-center-left':
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x);
break;
case 'box-bottom-left':
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x);
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y);
break;
case 'box-bottom-center':
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y);
break;
case 'box-center-right':
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x);
break;
case 'box-bottom-right':
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x);
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y);
break;
default:
}
return;
}
if (this.isBoxMoving) {
this.isFullScreen = false;
this.isMaxShowing = false;
this.nowRect.left = this.startRect.left + (e.clientX - this.startPosition.x);
this.nowRect.right = this.startRect.right - (e.clientX - this.startPosition.x);
this.nowRect.top = this.startRect.top + (e.clientY - this.startPosition.y);
this.nowRect.bottom = this.startRect.bottom - (e.clientY - this.startPosition.y);
return;
}
},
resizeMouseDown(e) {
if (this.app.disableResize) {
return;
}
if (this.isFullScreen || this.isMaxShowing) {
return;
}
this.startRect = {
left: this.nowRect.left,
top: this.nowRect.top,
right: this.nowRect.right,
bottom: this.nowRect.bottom,
};
this.startPosition.x = e.clientX;
this.startPosition.y = e.clientY;
this.isBoxResizing = true;
this.moveDirection = e.target.className;
},
},
};
</script>
<style scoped>
.iframe {
width: 100%;
height: calc(100% - 50px);
margin-top: 5px;
border-right: 5px;
}
.moveBg {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.box {
--resize: 5px;
--resize-bg: transparent;
--resize-main: transparent;
--resize-bg-main: transparent;
}
.box {
position: absolute;
pointer-events: auto;
display: flex;
flex-direction: column;
}
.box-top {
display: flex;
flex-direction: row;
}
.box-top-left {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: nw-resize;
}
.box-top-center {
height: var(--resize);
background: var(--resize-bg-main);
cursor: n-resize;
flex-grow: 1;
}
.box-top-right {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: ne-resize;
}
.box-center {
display: flex;
flex-direction: row;
flex-grow: 1;
}
.box-center-left {
width: var(--resize);
height: 100%;
background: var(--resize-bg-main);
cursor: w-resize;
}
.box-center-center {
height: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
border-radius: 10px;
box-shadow: 0px 0px 3px #999;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(20px);
overflow: hidden;
}
.isTop .box-center-center {
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.5);
filter: none;
}
.box-animation {
transition: width 0.1s, height 0.1s, left 0.1s, right 0.1s, top 0.1s, bottom 0.1s;
}
.isMaxShowing {
left: -5px !important;
right: -5px !important;
top: 24px !important;
bottom: 47px !important;
height: calc(100% - 24px);
}
.isFullScreen {
position: fixed !important;
z-index: 999 !important;
bottom: -5px !important;
}
.isMaxShowing .box-center-center,
.isFullScreen .box-center-center {
border-radius: 0px !important;
}
.box-center-right {
width: var(--resize);
height: 100%;
background: var(--resize-bg-main);
cursor: e-resize;
}
.box-bottom {
display: flex;
flex-direction: row;
}
.box-bottom-left {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: sw-resize;
}
.box-bottom-center {
height: var(--resize);
background: var(--resize-bg-main);
cursor: s-resize;
flex-grow: 1;
}
.box-bottom-right {
width: var(--resize);
height: var(--resize);
background: var(--resize-bg);
cursor: se-resize;
}
.loader {
display: flex;
flex-grow: 1;
flex-direction: column;
width: 100%;
}
.app-bar {
height: 40px;
background: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(20px);
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.app-bar .controll {
display: flex;
justify-content: center;
align-items: center;
margin-left: 15px;
}
.app-bar .controll div {
border-radius: 100%;
height: 11px;
width: 11px;
margin-right: 8px;
cursor: pointer;
}
.app-bar .title {
flex-grow: 1;
text-align: center;
margin-right: 80px;
font-weight: 500;
text-shadow: none;
font-size: 13px;
cursor: move;
color: #333;
}
.controll .close {
background: #fc605c;
border: 1px solid #fc635d;
}
.controll .min {
background: #fcbb40;
border: 1px solid #f8b438;
}
.controll .full {
background: #34c648;
border: 1px solid #2bc03f;
}
.full-disabled {
background: #ccc !important;
border: 1px solid #ccc !important;
}
.resize-disabled .box-top-left,
.resize-disabled .box-top-center,
.resize-disabled .box-top-right,
.resize-disabled .box-center-left,
.resize-disabled .box-center-right,
.resize-disabled .box-bottom-left,
.resize-disabled .box-bottom-center,
.resize-disabled .box-bottom-right {
cursor: default;
}
.app-body {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>