feat(sidebar): add tooltip for sidebar button

This commit is contained in:
AkiChase 2025-03-17 16:11:51 +08:00
parent 6eac5c8875
commit 3bb71df47e
7 changed files with 286 additions and 212 deletions

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import Sidebar from "./components/Sidebar.vue";
import Sidebar from "./components/sidebar/Sidebar.vue";
import Header from "./components/Header.vue";
import {
darkTheme,

View File

@ -1,209 +0,0 @@
<script setup lang="ts">
import { useRouter, useRoute } from "vue-router";
import {
GameControllerOutline,
LogoAndroid,
SettingsOutline,
ReturnDownBackOutline,
VolumeHighOutline,
VolumeLowOutline,
StopOutline,
ListOutline,
BulbOutline,
Bulb,
} from "@vicons/ionicons5";
import { Keyboard24Regular } from "@vicons/fluent";
import { NIcon, useMessage } from "naive-ui";
import { useGlobalStore } from "../store/global";
import { sendSetScreenPowerMode } from "../frontcommand/controlMsg";
import { AndroidKeycode } from "../frontcommand/android";
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { SendKeyAction, sendKey } from "../frontcommand/scrcpyMaskCmd";
const { t } = useI18n();
const router = useRouter();
const route = useRoute();
const store = useGlobalStore();
const message = useMessage();
const nextScreenPowerMode = ref(0);
function nav(name: string) {
router.replace({ name });
}
async function sendKeyCodeToDevice(code: AndroidKeycode) {
if (store.controledDevice) {
await sendKey({
action: SendKeyAction.Default,
keycode: code,
});
} else {
message.error(t("sidebar.noControledDevice"));
}
}
async function changeScreenPowerMode() {
if (store.controledDevice) {
sendSetScreenPowerMode({ mode: nextScreenPowerMode.value });
nextScreenPowerMode.value = nextScreenPowerMode.value ? 0 : 2;
} else {
message.error(t("sidebar.noControledDevice"));
}
}
</script>
<template>
<div class="sidebar">
<div data-tauri-drag-region class="logo">S M</div>
<div class="module">
<div :class="{ active: route.name == 'mask' }" @click="nav('mask')">
<NIcon>
<GameControllerOutline />
</NIcon>
</div>
<div :class="{ active: route.name == 'device' }" @click="nav('device')">
<NIcon>
<LogoAndroid />
</NIcon>
</div>
<div
:class="{ active: route.name == 'keyboard' }"
@click="nav('keyboard')"
>
<NIcon>
<Keyboard24Regular />
</NIcon>
</div>
<div :class="{ active: route.name == 'setting' }" @click="nav('setting')">
<NIcon>
<SettingsOutline />
</NIcon>
</div>
</div>
<div data-tauri-drag-region class="drag"></div>
<div class="nav">
<div @click="changeScreenPowerMode">
<NIcon>
<Bulb v-if="nextScreenPowerMode" />
<BulbOutline v-else />
</NIcon>
</div>
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_VOLUME_UP)">
<NIcon>
<VolumeHighOutline />
</NIcon>
</div>
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_VOLUME_DOWN)">
<NIcon>
<VolumeLowOutline />
</NIcon>
</div>
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_BACK)">
<NIcon>
<ReturnDownBackOutline />
</NIcon>
</div>
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_HOME)">
<NIcon>
<StopOutline />
</NIcon>
</div>
<div @click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_APP_SWITCH)">
<NIcon>
<ListOutline />
</NIcon>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.sidebar {
background-color: var(--bg-color);
border-right: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 10px 0 0 10px;
grid-area: sidebar;
display: flex;
flex-direction: column;
justify-content: space-between;
user-select: none;
-webkit-user-select: none;
.logo {
height: 30px;
font-size: 18px;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
color: var(--light-color);
cursor: pointer;
}
.drag{
flex-grow: 1;
width: 100%;
}
.module {
display: flex;
flex-direction: column;
& > div {
flex-shrink: 0;
height: 50px;
color: var(--gray-color);
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.3s ease;
box-sizing: border-box;
font-size: 28px;
cursor: pointer;
&:hover {
color: var(--primary-hover-color);
transform: scale(1.05);
}
&:active {
color: var(--primary-pressed-color);
transform: scale(0.9);
}
}
& > div.active {
color: var(--primary-color);
border-left: 3px solid var(--primary-color);
border-radius: 3px;
}
}
.nav {
color: var(--light-color);
font-size: 20px;
display: flex;
flex-direction: column;
flex-shrink: 0;
& > div {
height: 40px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: transform 0.3s ease;
&:hover {
color: var(--primary-hover-color);
transform: scale(1.1);
}
&:active {
color: var(--primary-pressed-color);
transform: scale(0.9);
}
}
}
}
</style>

View File

@ -0,0 +1,40 @@
<script setup lang="ts">
import { NIcon, NTooltip } from "naive-ui";
const props = defineProps<{
icon: Object;
tip: string;
}>();
</script>
<template>
<div class="btn-content">
<NTooltip trigger="hover">
<template #trigger>
<NIcon><component :is="props.icon" /></NIcon>
</template>
{{ props.tip }}
</NTooltip>
</div>
</template>
<style lang="scss" scoped>
.btn-content {
height: 40px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: transform 0.3s ease;
&:hover {
color: var(--primary-hover-color);
transform: scale(1.1);
}
&:active {
color: var(--primary-pressed-color);
transform: scale(0.9);
}
}
</style>

View File

@ -0,0 +1,63 @@
<script setup lang="ts">
import { NIcon, NTooltip } from "naive-ui";
import { useRoute, useRouter } from "vue-router";
const props = defineProps<{
name: string;
icon: Object;
tip: string;
}>();
const router = useRouter();
const route = useRoute();
function nav(name: string) {
router.replace({ name });
}
</script>
<template>
<div
:class="{
'nav-active': route.name === props.name,
'nav-content': true,
}"
@click="nav(props.name)"
>
<NTooltip trigger="hover">
<template #trigger>
<NIcon><component :is="props.icon" /></NIcon>
</template>
{{ props.tip }}
</NTooltip>
</div>
</template>
<style lang="scss" scoped>
.nav-content {
flex-shrink: 0;
height: 50px;
color: var(--gray-color);
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.3s ease;
box-sizing: border-box;
font-size: 28px;
cursor: pointer;
&:hover {
color: var(--primary-hover-color);
transform: scale(1.05);
}
&:active {
color: var(--primary-pressed-color);
transform: scale(0.9);
}
}
.nav-active {
color: var(--primary-color);
border-left: 3px solid var(--primary-color);
border-radius: 3px;
}
</style>

View File

@ -0,0 +1,154 @@
<script setup lang="ts">
import {
GameControllerOutline,
LogoAndroid,
SettingsOutline,
ReturnDownBackOutline,
VolumeHighOutline,
VolumeLowOutline,
StopOutline,
ListOutline,
BulbOutline,
Bulb,
} from "@vicons/ionicons5";
import { Keyboard24Regular } from "@vicons/fluent";
import { useMessage } from "naive-ui";
import { useGlobalStore } from "../../store/global";
import { sendSetScreenPowerMode } from "../../frontcommand/controlMsg";
import { AndroidKeycode } from "../../frontcommand/android";
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { SendKeyAction, sendKey } from "../../frontcommand/scrcpyMaskCmd";
import ModuleNav from "./ModuleNav.vue";
import FuncButton from "./FuncButton.vue";
const { t } = useI18n();
const store = useGlobalStore();
const message = useMessage();
const nextScreenPowerMode = ref(0);
async function sendKeyCodeToDevice(code: AndroidKeycode) {
if (store.controledDevice) {
await sendKey({
action: SendKeyAction.Default,
keycode: code,
});
} else {
message.error(t("sidebar.noControledDevice"));
}
}
async function changeScreenPowerMode() {
if (store.controledDevice) {
sendSetScreenPowerMode({ mode: nextScreenPowerMode.value });
nextScreenPowerMode.value = nextScreenPowerMode.value ? 0 : 2;
} else {
message.error(t("sidebar.noControledDevice"));
}
}
</script>
<template>
<div class="sidebar">
<div data-tauri-drag-region class="logo">S M</div>
<div class="module-nav">
<ModuleNav
name="mask"
:icon="GameControllerOutline"
:tip="t('sidebar.tip.mask')"
/>
<ModuleNav
name="device"
:icon="LogoAndroid"
:tip="t('sidebar.tip.device')"
/>
<ModuleNav
name="keyboard"
:icon="Keyboard24Regular"
:tip="t('sidebar.tip.keyboard')"
/>
<ModuleNav
name="setting"
:icon="SettingsOutline"
:tip="t('sidebar.tip.setting')"
/>
</div>
<div data-tauri-drag-region class="drag" />
<div class="func-btn">
<FuncButton
@click="changeScreenPowerMode"
:tip="nextScreenPowerMode? t('sidebar.tip.screenPowerModeOff'): t('sidebar.tip.screenPowerModeOn')"
:icon="nextScreenPowerMode ? Bulb : BulbOutline"
/>
<FuncButton
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_VOLUME_UP)"
:tip="t('sidebar.tip.volumeUp')"
:icon="VolumeHighOutline"
/>
<FuncButton
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_VOLUME_DOWN)"
:tip="t('sidebar.tip.volumeDown')"
:icon="VolumeLowOutline"
/>
<FuncButton
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_BACK)"
:tip="t('sidebar.tip.back')"
:icon="ReturnDownBackOutline"
/>
<FuncButton
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_HOME)"
:tip="t('sidebar.tip.home')"
:icon="StopOutline"
/>
<FuncButton
@click="sendKeyCodeToDevice(AndroidKeycode.AKEYCODE_APP_SWITCH)"
:tip="t('sidebar.tip.appSwitch')"
:icon="ListOutline"
/>
</div>
</div>
</template>
<style scoped lang="scss">
.sidebar {
background-color: var(--bg-color);
border-right: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 10px 0 0 10px;
grid-area: sidebar;
display: flex;
flex-direction: column;
justify-content: space-between;
user-select: none;
-webkit-user-select: none;
.logo {
height: 30px;
font-size: 18px;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
color: var(--light-color);
cursor: pointer;
}
.drag {
flex-grow: 1;
width: 100%;
}
.module-nav {
display: flex;
flex-direction: column;
}
.func-btn {
color: var(--light-color);
font-size: 20px;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
}
</style>

View File

@ -282,7 +282,20 @@
}
},
"sidebar": {
"noControledDevice": "No devices are controlled"
"noControledDevice": "No devices are controlled",
"tip": {
"mask": "Mask",
"device": "Device",
"keyboard": "Key mapping",
"setting": "Setting",
"screenPowerModeOff": "Screen off",
"screenPowerModeOn": "Screen on",
"volumeUp": "Volume up",
"volumeDown": "Volume down",
"back": "Back",
"home": "Home",
"appSwitch": "App switch"
}
},
"websocket": {
"open": "Connected to external control server",

View File

@ -282,7 +282,20 @@
}
},
"sidebar": {
"noControledDevice": "未控制任何设备"
"noControledDevice": "未控制任何设备",
"tip": {
"mask": "蒙版",
"device": "设备",
"keyboard": "按键映射",
"setting": "设置",
"screenPowerModeOff": "息屏",
"screenPowerModeOn": "亮屏",
"volumeUp": "增加音量",
"volumeDown": "减少音量",
"back": "返回",
"home": "主页",
"appSwitch": "最近任务"
}
},
"websocket": {
"open": "已连接到外部控制服务端",