feat(components/Navbar): 自訂和微調各系統的 titlebar (#1343)

* feat: linux custom titlebar
* add settings init
* Update zh-TW.js
* fix: color

Co-authored-by: memorydream <34763046+memorydream@users.noreply.github.com>
master
pan93412 3 years ago committed by GitHub
parent 3e1dc62fa0
commit 3d5d40c476
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

@ -180,7 +180,10 @@ class Background {
minWidth: 1080,
minHeight: 720,
titleBarStyle: 'hiddenInset',
frame: !isWindows,
frame: !(
isWindows ||
(isLinux && this.store.get('settings.linuxEnableCustomTitlebar'))
),
title: 'YesPlayMusic',
show: false,
webPreferences: {

@ -0,0 +1,132 @@
<template>
<div class="linux-titlebar">
<div class="logo">
<img src="img/logos/yesplaymusic-white24x24.png" />
</div>
<div class="title">{{ title }}</div>
<div class="controls">
<div
class="button minimize codicon codicon-chrome-minimize"
@click="windowMinimize"
></div>
<div
class="button max-restore codicon"
:class="{
'codicon-chrome-restore': !isShowMaximized,
'codicon-chrome-maximize': isShowMaximized,
}"
@click="windowMaxRestore"
></div>
<div
class="button close codicon codicon-chrome-close"
@click="windowClose"
></div>
</div>
</div>
</template>
<script>
// icons by https://github.com/microsoft/vscode-codicons
import 'vscode-codicons/dist/codicon.css';
import { mapState } from 'vuex';
const electron =
process.env.IS_ELECTRON === true ? window.require('electron') : null;
const ipcRenderer =
process.env.IS_ELECTRON === true ? electron.ipcRenderer : null;
export default {
name: 'LinuxTitlebar',
data() {
return {
isShowMaximized: true,
};
},
computed: {
...mapState(['title']),
},
created() {
if (process.env.IS_ELECTRON === true) {
ipcRenderer.on('isMaximized', (_, value) => {
// valuefalse
// valuetrue
this.isShowMaximized = value;
});
}
},
methods: {
windowMinimize() {
ipcRenderer.send('minimize');
},
windowMaxRestore() {
ipcRenderer.send('maximizeOrUnmaximize');
},
windowClose() {
ipcRenderer.send('close');
},
},
};
</script>
<style lang="scss" scoped>
.linux-titlebar {
color: var(--color-text);
position: fixed;
left: 0;
top: 0;
right: 0;
-webkit-app-region: drag;
display: flex;
align-items: center;
--hover: #e6e6e6;
--active: #cccccc;
.logo {
padding: 0 8px;
}
.title {
padding: 8px;
font-size: 12px;
font-family: 'Segoe UI', 'Microsoft YaHei UI', 'Microsoft YaHei', sans-serif;
justify-self: center;
margin: 0 auto;
}
.controls {
height: 32px;
//margin-left: auto;
justify-content: flex-end;
display: flex;
.button {
height: 100%;
width: 46px;
font-size: 16px;
display: flex;
justify-content: center;
align-items: center;
-webkit-app-region: no-drag;
&:hover {
background: var(--hover);
}
&:active {
background: var(--active);
}
&.close {
&:hover {
background: #c42c1b;
color: rgba(255, 255, 255, 0.8);
}
&:active {
background: #f1707a;
color: #000;
}
}
}
}
}
[data-theme='dark'] .linux-titlebar {
--hover: #191919;
--active: #333333;
}
</style>

@ -1,27 +1,8 @@
<template>
<div>
<nav>
<div class="win32-titlebar">
<div class="title">YesPlayMusic</div>
<div class="controls">
<div
class="button minimize codicon codicon-chrome-minimize"
@click="windowMinimize"
></div>
<div
class="button max-restore codicon"
:class="{
'codicon-chrome-restore': !isWindowMaximized,
'codicon-chrome-maximize': isWindowMaximized,
}"
@click="windowMaxRestore"
></div>
<div
class="button close codicon codicon-chrome-close"
@click="windowClose"
></div>
</div>
</div>
<nav :class="{ 'has-custom-titlebar': hasCustomTitlebar }">
<Win32Titlebar v-if="enableWin32Titlebar" />
<LinuxTitlebar v-if="enableLinuxTitlebar" />
<div class="navigation-buttons">
<button-icon @click.native="go('back')"
><svg-icon icon-class="arrow-left"
@ -96,17 +77,16 @@ import { isLooseLoggedIn, doLogout } from '@/utils/auth';
// icons by https://github.com/microsoft/vscode-codicons
import 'vscode-codicons/dist/codicon.css';
import Win32Titlebar from '@/components/Win32Titlebar.vue';
import LinuxTitlebar from '@/components/LinuxTitlebar.vue';
import ContextMenu from '@/components/ContextMenu.vue';
import ButtonIcon from '@/components/ButtonIcon.vue';
const electron =
process.env.IS_ELECTRON === true ? window.require('electron') : null;
const ipcRenderer =
process.env.IS_ELECTRON === true ? electron.ipcRenderer : null;
export default {
name: 'Navbar',
components: {
Win32Titlebar,
LinuxTitlebar,
ButtonIcon,
ContextMenu,
},
@ -115,7 +95,8 @@ export default {
inputFocus: false,
langs: ['zh-CN', 'zh-TW', 'en', 'tr'],
keywords: '',
isWindowMaximized: false,
enableWin32Titlebar: false,
enableLinuxTitlebar: false,
};
},
computed: {
@ -128,12 +109,18 @@ export default {
? `${this.data?.user?.avatarUrl}?param=512y512`
: 'http://s4.music.126.net/style/web2/img/default/default_avatar.jpg?param=60y60';
},
hasCustomTitlebar() {
return this.enableWin32Titlebar || this.enableLinuxTitlebar;
},
},
created() {
if (process.env.IS_ELECTRON === true) {
ipcRenderer.on('isMaximized', (event, value) => {
this.isWindowMaximized = value;
});
if (process.platform === 'win32') {
this.enableWin32Titlebar = true;
} else if (
process.platform === 'linux' &&
this.settings.linuxEnableCustomTitlebar
) {
this.enableLinuxTitlebar = true;
}
},
methods: {
@ -175,15 +162,6 @@ export default {
this.$router.push({ name: 'login' });
}
},
windowMinimize() {
ipcRenderer.send('minimize');
},
windowMaxRestore() {
ipcRenderer.send('maximizeOrUnmaximize');
},
windowClose() {
ipcRenderer.send('close');
},
},
};
</script>
@ -221,69 +199,10 @@ nav {
}
}
.win32-titlebar {
display: none;
}
[data-electron-os='win32'] {
nav {
nav.has-custom-titlebar {
padding-top: 20px;
-webkit-app-region: no-drag;
}
.win32-titlebar {
color: var(--color-text);
position: fixed;
left: 0;
top: 0;
right: 0;
-webkit-app-region: drag;
display: flex;
align-items: center;
--hover: #e6e6e6;
--active: #cccccc;
.title {
padding: 8px;
font-size: 12px;
font-family: 'Segoe UI', 'Microsoft YaHei UI', 'Microsoft YaHei',
sans-serif;
}
.controls {
height: 32px;
margin-left: auto;
justify-content: flex-end;
display: flex;
.button {
height: 100%;
width: 46px;
font-size: 16px;
display: flex;
justify-content: center;
align-items: center;
-webkit-app-region: no-drag;
&:hover {
background: var(--hover);
}
&:active {
background: var(--active);
}
&.close {
&:hover {
background: rgba(232, 17, 35, 0.9);
}
&:active {
background: #f1707a;
color: #000;
}
}
}
}
}
&[data-theme='dark'] .win32-titlebar {
--hover: #191919;
--active: #333333;
}
}
.navigation-buttons {
flex: 1;

@ -0,0 +1,123 @@
<template>
<div class="win32-titlebar">
<div class="title">{{ title }}</div>
<div class="controls">
<div
class="button minimize codicon codicon-chrome-minimize"
@click="windowMinimize"
></div>
<div
class="button max-restore codicon"
:class="{
'codicon-chrome-restore': !isShowMaximized,
'codicon-chrome-maximize': isShowMaximized,
}"
@click="windowMaxRestore"
></div>
<div
class="button close codicon codicon-chrome-close"
@click="windowClose"
></div>
</div>
</div>
</template>
<script>
// icons by https://github.com/microsoft/vscode-codicons
import 'vscode-codicons/dist/codicon.css';
import { mapState } from 'vuex';
const electron =
process.env.IS_ELECTRON === true ? window.require('electron') : null;
const ipcRenderer =
process.env.IS_ELECTRON === true ? electron.ipcRenderer : null;
export default {
name: 'Win32Titlebar',
data() {
return {
isShowMaximized: true,
};
},
computed: {
...mapState(['title']),
},
created() {
if (process.env.IS_ELECTRON === true) {
ipcRenderer.on('isMaximized', (_, value) => {
// valuefalse
// valuetrue
this.isShowMaximized = value;
});
}
},
methods: {
windowMinimize() {
ipcRenderer.send('minimize');
},
windowMaxRestore() {
ipcRenderer.send('maximizeOrUnmaximize');
},
windowClose() {
ipcRenderer.send('close');
},
},
};
</script>
<style lang="scss" scoped>
.win32-titlebar {
color: var(--color-text);
position: fixed;
left: 0;
top: 0;
right: 0;
-webkit-app-region: drag;
display: flex;
align-items: center;
--hover: #e6e6e6;
--active: #cccccc;
.title {
padding: 8px 12px;
font-size: 12px;
font-family: 'Segoe UI', 'Microsoft YaHei UI', 'Microsoft YaHei', sans-serif;
}
.controls {
height: 32px;
margin-left: auto;
justify-content: flex-end;
display: flex;
.button {
height: 100%;
width: 46px;
font-size: 16px;
display: flex;
justify-content: center;
align-items: center;
-webkit-app-region: no-drag;
&:hover {
background: var(--hover);
}
&:active {
background: var(--active);
}
&.close {
&:hover {
background: #c42c1b;
color: rgba(255, 255, 255, 0.8);
}
&:active {
background: #f1707a;
color: #000;
}
}
}
}
}
[data-theme='dark'] .win32-titlebar {
--hover: #191919;
--active: #333333;
}
</style>

@ -158,6 +158,7 @@ export default {
showLibraryDefault: 'Show Library after App Launched',
subTitleDefault: 'Show Alias for Subtitle by default',
enableReversedMode: 'Enable Reversed Mode (Experimental)',
enableCustomTitlebar: 'Enable custom title bar (Need restart)',
lyricsBackground: {
text: 'Show Lyrics Background',
off: 'Off',

@ -150,7 +150,9 @@ export default {
showPlaylistsByAppleMusic: "Apple Music'in Çalma Listelerini Göster",
enableDiscordRichPresence: 'Discord gösterimini aktifleştir',
showLibraryDefault: 'Kitaplık Varsayılanını göster',
subTitleDefault: 'Sub title alia default',
subTitleDefault: 'Show Alias for Subtitle by default',
enableReversedMode: 'Enable Reversed Mode (Experimental)',
enableCustomTitlebar: 'Enable custom title bar (Need restart)',
lyricsBackground: {
text: 'Şarkı Sözleri Arka Planını Göster',
off: 'kapalı',

@ -159,6 +159,7 @@ export default {
showLibraryDefault: '启动后显示音乐库',
subTitleDefault: '副标题使用别名',
enableReversedMode: '启用倒序播放功能 (实验性功能)',
enableCustomTitlebar: '启用自定义标题栏 (重启后生效)',
lyricsBackground: {
text: '显示歌词背景',
off: '关闭',

@ -156,6 +156,7 @@ export default {
showLibraryDefault: '啟動後顯示音樂庫',
subTitleDefault: '副標題使用別名',
enableReversedMode: '啟用倒序播放功能 (實驗性功能)',
enableCustomTitlebar: '啟用自訂標題列(重新啟動後生效)',
lyricsBackground: {
text: '顯示歌詞背景',
off: '關閉',

@ -28,6 +28,7 @@ let localStorage = {
enableGlobalShortcut: true,
showLibraryDefault: false,
subTitleDefault: false,
linuxEnableCustomTitlebar: false,
enabledPlaylistCategories,
proxyConfig: {
protocol: 'noProxy',

@ -72,4 +72,7 @@ export default {
enableScrolling(state, status = null) {
state.enableScrolling = status ? status : !state.enableScrolling;
},
updateTitle(state, title) {
state.title = title;
},
};

@ -13,6 +13,7 @@ updateApp();
export default {
showLyrics: false,
enableScrolling: true,
title: 'YesPlayMusic',
liked: {
songs: [],
songsWithDetails: [], // 只有前12首

@ -34,6 +34,7 @@ function setTitle(track) {
if (isCreateTray) {
ipcRenderer.send('updateTrayTooltip', document.title);
}
store.commit('updateTitle', document.title);
}
function setTrayLikeState(isLiked) {

@ -331,6 +331,23 @@
</div>
</div>
<div v-if="isElectron && isLinux" class="item">
<div class="left">
<div class="title"> {{ $t('settings.enableCustomTitlebar') }} </div>
</div>
<div class="right">
<div class="toggle">
<input
id="enable-custom-titlebar"
v-model="enableCustomTitlebar"
type="checkbox"
name="enable-custom-titlebar"
/>
<label for="enable-custom-titlebar"></label>
</div>
</div>
</div>
<div v-if="isElectron" class="item">
<div class="left">
<div class="title"> {{ $t('settings.showLibraryDefault') }}</div>
@ -592,6 +609,9 @@ export default {
isMac() {
return /macintosh|mac os x/i.test(navigator.userAgent);
},
isLinux() {
return process.platform === 'linux';
},
version() {
return pkg.version;
},
@ -928,6 +948,17 @@ export default {
});
},
},
enableCustomTitlebar: {
get() {
return this.settings.linuxEnableCustomTitlebar;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'linuxEnableCustomTitlebar',
value,
});
},
},
isLastfmConnected() {
return this.lastfm.key !== undefined;
},

Loading…
Cancel
Save