feat: hr indicator, adjust color theme
This commit is contained in:
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -18,10 +18,13 @@ declare module 'vue' {
|
|||||||
SystemUiconsSignalFull: typeof import('./src/components/icons/SystemUiconsSignalFull.vue')['default']
|
SystemUiconsSignalFull: typeof import('./src/components/icons/SystemUiconsSignalFull.vue')['default']
|
||||||
SystemUiconsSignalLow: typeof import('./src/components/icons/SystemUiconsSignalLow.vue')['default']
|
SystemUiconsSignalLow: typeof import('./src/components/icons/SystemUiconsSignalLow.vue')['default']
|
||||||
SystemUiconsSignalMedium: typeof import('./src/components/icons/SystemUiconsSignalMedium.vue')['default']
|
SystemUiconsSignalMedium: typeof import('./src/components/icons/SystemUiconsSignalMedium.vue')['default']
|
||||||
|
TablerActivityHeartbeat: typeof import('./src/components/icons/TablerActivityHeartbeat.vue')['default']
|
||||||
TablerBluetooth: typeof import('./src/components/icons/TablerBluetooth.vue')['default']
|
TablerBluetooth: typeof import('./src/components/icons/TablerBluetooth.vue')['default']
|
||||||
TablerBluetoothConnected: typeof import('./src/components/icons/TablerBluetoothConnected.vue')['default']
|
TablerBluetoothConnected: typeof import('./src/components/icons/TablerBluetoothConnected.vue')['default']
|
||||||
TablerBluetoothOff: typeof import('./src/components/icons/TablerBluetoothOff.vue')['default']
|
TablerBluetoothOff: typeof import('./src/components/icons/TablerBluetoothOff.vue')['default']
|
||||||
TablerBluetoothX: typeof import('./src/components/icons/TablerBluetoothX.vue')['default']
|
TablerBluetoothX: typeof import('./src/components/icons/TablerBluetoothX.vue')['default']
|
||||||
|
TablerCaretDownFilled: typeof import('./src/components/icons/TablerCaretDownFilled.vue')['default']
|
||||||
|
TablerCaretUpFilled: typeof import('./src/components/icons/TablerCaretUpFilled.vue')['default']
|
||||||
TablerDeviceWatch: typeof import('./src/components/icons/TablerDeviceWatch.vue')['default']
|
TablerDeviceWatch: typeof import('./src/components/icons/TablerDeviceWatch.vue')['default']
|
||||||
TablerReload: typeof import('./src/components/icons/TablerReload.vue')['default']
|
TablerReload: typeof import('./src/components/icons/TablerReload.vue')['default']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,7 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
use btleplug::api::bleuuid::uuid_from_u16;
|
use btleplug::api::bleuuid::uuid_from_u16;
|
||||||
use btleplug::api::CentralEvent::{
|
use btleplug::api::CentralEvent::{DeviceDisconnected, DeviceDiscovered, DeviceUpdated};
|
||||||
DeviceConnected, DeviceDisconnected, DeviceDiscovered, DeviceUpdated,
|
|
||||||
ManufacturerDataAdvertisement, ServiceDataAdvertisement, ServicesAdvertisement,
|
|
||||||
};
|
|
||||||
use btleplug::api::{BDAddr, Central, Manager as _, Peripheral as _, ScanFilter};
|
use btleplug::api::{BDAddr, Central, Manager as _, Peripheral as _, ScanFilter};
|
||||||
use btleplug::platform::{Adapter, Manager as BtleManager, Peripheral, PeripheralId};
|
use btleplug::platform::{Adapter, Manager as BtleManager, Peripheral, PeripheralId};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
@@ -88,6 +85,7 @@ impl BleConnection {
|
|||||||
{
|
{
|
||||||
return Err("Peripheral does not have the required service".into());
|
return Err("Peripheral does not have the required service".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_peripheral(Some(peripheral)).await;
|
self.set_peripheral(Some(peripheral)).await;
|
||||||
|
|
||||||
let peripheral = self.peripheral.lock().await;
|
let peripheral = self.peripheral.lock().await;
|
||||||
@@ -110,6 +108,40 @@ impl BleConnection {
|
|||||||
.rssi
|
.rssi
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let service = peripheral
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.services()
|
||||||
|
.into_iter()
|
||||||
|
.find(|s| s.uuid == uuid_from_u16(0x180D))
|
||||||
|
.unwrap();
|
||||||
|
let characteristic = service
|
||||||
|
.characteristics
|
||||||
|
.into_iter()
|
||||||
|
.find(|c| c.uuid == uuid_from_u16(0x2A37))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let peripheral = peripheral.clone();
|
||||||
|
peripheral
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.subscribe(&characteristic)
|
||||||
|
.await?;
|
||||||
|
let app_clone = app.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut notification_stream =
|
||||||
|
peripheral.as_ref().unwrap().notifications().await.unwrap();
|
||||||
|
while let Some(notification) = notification_stream.next().await {
|
||||||
|
if notification.uuid == uuid_from_u16(0x2A37) {
|
||||||
|
let value = notification.value;
|
||||||
|
let heart_rate = value[1] as u16;
|
||||||
|
app_clone.emit_all("heart-rate", heart_rate).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.emit_all("device-connected", device).unwrap();
|
app.emit_all("device-connected", device).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -127,7 +159,7 @@ impl BleConnection {
|
|||||||
let app_handle = app.clone(); // Clone the AppHandle to move into the tokio::spawn closure
|
let app_handle = app.clone(); // Clone the AppHandle to move into the tokio::spawn closure
|
||||||
let mut event_stream = central.as_ref().unwrap().events().await.unwrap();
|
let mut event_stream = central.as_ref().unwrap().events().await.unwrap();
|
||||||
|
|
||||||
let mut self_clone = self.clone(); // Clone the BleConnection to move into the tokio::spawn closure
|
let self_clone = self.clone(); // Clone the BleConnection to move into the tokio::spawn closure
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while let Some(event) = event_stream.next().await {
|
while let Some(event) = event_stream.next().await {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
"distDir": "../dist"
|
"distDir": "../dist"
|
||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "heartbeat-cat",
|
"productName": "HBCat",
|
||||||
"version": "0.0.1"
|
"version": "1.0.1"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
@@ -37,7 +37,8 @@
|
|||||||
"minWidth": 800,
|
"minWidth": 800,
|
||||||
"minHeight": 500,
|
"minHeight": 500,
|
||||||
"width": 800,
|
"width": 800,
|
||||||
"height": 500
|
"height": 500,
|
||||||
|
"userAgent": "Heartbeat Cat"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"security": {
|
"security": {
|
||||||
@@ -47,9 +48,20 @@
|
|||||||
"active": true,
|
"active": true,
|
||||||
"targets": "all",
|
"targets": "all",
|
||||||
"identifier": "ga.bh8.heartbeat-cat",
|
"identifier": "ga.bh8.heartbeat-cat",
|
||||||
|
"publisher": "TimothyYin",
|
||||||
|
"copyright": "2024 TimothyYin",
|
||||||
|
"category": "Utility",
|
||||||
|
"shortDescription": "HBCat",
|
||||||
|
"longDescription": "Catch your heartbeat",
|
||||||
"icon": [
|
"icon": [
|
||||||
"icons/icon.ico"
|
"icons/icon.ico"
|
||||||
]
|
],
|
||||||
|
"windows": {
|
||||||
|
"nsis": {
|
||||||
|
"installerIcon": "icons/icon.ico",
|
||||||
|
"installMode": "both"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,6 @@ const store = useBrcatStore();
|
|||||||
|
|
||||||
invoke("register_central_events");
|
invoke("register_central_events");
|
||||||
|
|
||||||
listen("heart-rate", (hr) => {
|
|
||||||
console.log('Heart Rate', hr);
|
|
||||||
})
|
|
||||||
|
|
||||||
listen("scan-list-update", (event) => {
|
listen("scan-list-update", (event) => {
|
||||||
console.log('scan-list-update', event.payload);
|
console.log('scan-list-update', event.payload);
|
||||||
})
|
})
|
||||||
@@ -52,7 +48,7 @@ listen("device-disconnected", (event) => {
|
|||||||
--app-background: #f8f8f8;
|
--app-background: #f8f8f8;
|
||||||
|
|
||||||
--title-bar-background: #e4e4e4;
|
--title-bar-background: #e4e4e4;
|
||||||
--title-bar-color: #F25E86;
|
--title-bar-color: var(--primary-color);
|
||||||
--title-bar-height: 25px;
|
--title-bar-height: 25px;
|
||||||
|
|
||||||
--drawer-bar-background: #eeeeee;
|
--drawer-bar-background: #eeeeee;
|
||||||
|
|||||||
@@ -71,7 +71,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
border: none;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
min-width: 30px;
|
min-width: 30px;
|
||||||
@@ -79,7 +78,6 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #F25E86;
|
|
||||||
-webkit-border-radius: 4px;
|
-webkit-border-radius: 4px;
|
||||||
-moz-border-radius: 4px;
|
-moz-border-radius: 4px;
|
||||||
-ms-border-radius: 4px;
|
-ms-border-radius: 4px;
|
||||||
@@ -90,22 +88,19 @@
|
|||||||
-moz-transition: all .3s ease;
|
-moz-transition: all .3s ease;
|
||||||
-ms-transition: all .3s ease;
|
-ms-transition: all .3s ease;
|
||||||
-o-transition: all .3s ease;
|
-o-transition: all .3s ease;
|
||||||
@apply text-xs;
|
@apply text-xs bg-primary border-0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.outline {
|
.btn.outline {
|
||||||
background-color: transparent;
|
@apply text-primary bg-transparent border border-primary shadow-none;
|
||||||
color: #F25E86;
|
|
||||||
border: 1px solid #F25E86;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:hover {
|
.btn:hover {
|
||||||
box-shadow: 2px 2px 6px 1px rgb(0 0 0 / 20%);
|
box-shadow: 2px 2px 6px 1px rgb(0 0 0 / .1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:active {
|
.btn:active {
|
||||||
box-shadow: 2px 2px 6px 1px rgb(0 0 0 / 20%), 2px 2px 6px 1px rgb(0 0 0 / 20%) inset;
|
box-shadow: 2px 2px 6px 1px rgb(0 0 0 / .1), 2px 2px 6px 1px rgb(0 0 0 / .1) inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:disabled {
|
.btn:disabled {
|
||||||
|
|||||||
@@ -21,6 +21,26 @@ const navList = ref([
|
|||||||
<span>{{ item.title }}</span>
|
<span>{{ item.title }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Transition name="indicator" mode="out-in">
|
||||||
|
<div v-if="store.is_connected"
|
||||||
|
class="flex px-2 py-0.5 gap-1 justify-between items-center bg-neutral-200 border-b border-neutral-300">
|
||||||
|
<span class="inline-flex items-center gap-0.5 text-2xl text-primary font-bold">
|
||||||
|
<TablerActivityHeartbeat class="text-base" />
|
||||||
|
{{ store.current_heart_rate || '--' }}
|
||||||
|
</span>
|
||||||
|
<span class="flex flex-col gap-0.5 text-neutral-400">
|
||||||
|
<span class="flex items-center gap-1 text-xs leading-none">
|
||||||
|
<TablerCaretUpFilled />
|
||||||
|
<span>{{ '--' }}</span>
|
||||||
|
</span>
|
||||||
|
<span class="flex items-center gap-1 text-xs leading-none">
|
||||||
|
<TablerCaretDownFilled />
|
||||||
|
<span>{{ '--' }}</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<TablerBluetoothConnected v-if="store.is_connected" class="icon text-sm block -mt-0.5 text-emerald-500" />
|
<TablerBluetoothConnected v-if="store.is_connected" class="icon text-sm block -mt-0.5 text-emerald-500" />
|
||||||
<TablerBluetooth v-else class="icon text-sm block -mt-0.5 text-neutral-400" />
|
<TablerBluetooth v-else class="icon text-sm block -mt-0.5 text-neutral-400" />
|
||||||
@@ -29,6 +49,7 @@ const navList = ref([
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
@@ -36,6 +57,16 @@ const navList = ref([
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.indicator-enter-active,
|
||||||
|
.indicator-leave-active {
|
||||||
|
@apply transition-all duration-150;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator-enter-from,
|
||||||
|
.indicator-leave-to {
|
||||||
|
@apply opacity-0 translate-y-4;
|
||||||
|
}
|
||||||
|
|
||||||
.drawer {
|
.drawer {
|
||||||
background-color: var(--app-background);
|
background-color: var(--app-background);
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='hexagons' fill='%23ccc' fill-opacity='0.1' fill-rule='nonzero'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='hexagons' fill='%23ccc' fill-opacity='0.1' fill-rule='nonzero'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||||
@@ -54,13 +85,13 @@ const navList = ref([
|
|||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
/* background-color: var(--drawer-bar-item-active-background); */
|
/* background-color: var(--drawer-bar-item-active-background); */
|
||||||
@apply text-pink-400 border-l-4 border-pink-400 bg-pink-400/10 pl-0;
|
@apply text-primary-400 border-l-4 border-primary-400 bg-primary-400/10 pl-0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
@apply w-full h-8 bg-neutral-300 flex items-center text-neutral-900 px-2 text-2xs whitespace-nowrap flex-nowrap;
|
@apply w-full h-8 bg-neutral-200 flex items-center text-neutral-900 px-2 text-2xs whitespace-nowrap flex-nowrap;
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
@apply flex-1 overflow-hidden text-ellipsis;
|
@apply flex-1 overflow-hidden text-ellipsis;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ defineProps({
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col h-full">
|
<div class="flex flex-col h-full">
|
||||||
<header
|
<header
|
||||||
class="w-full h-11 px-4 flex justify-between items-center bg-gradient-to-r from-pink-50 to-pink-100 border-b">
|
class="w-full h-11 px-4 flex justify-between items-center bg-gradient-to-r from-primary-50 to-primary-100 border-b">
|
||||||
<div class="flex flex-col gap-0.5">
|
<div class="flex flex-col gap-0.5">
|
||||||
<h1 class="font-semibold text-neutral-900" :class="{ 'text-xs': !!subtitle, 'text-base': !subtitle }">
|
<h1 class="font-semibold text-neutral-900" :class="{ 'text-xs': !!subtitle, 'text-base': !subtitle }">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
|
|||||||
10
src/components/icons/TablerActivityHeartbeat.vue
Normal file
10
src/components/icons/TablerActivityHeartbeat.vue
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12h4.5L9 6l4 12l2-9l1.5 3H21"></path></svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TablerActivityHeartbeat'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
10
src/components/icons/TablerCaretDownFilled.vue
Normal file
10
src/components/icons/TablerCaretDownFilled.vue
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M18 9c.852 0 1.297.986.783 1.623l-.076.084l-6 6a1 1 0 0 1-1.32.083l-.094-.083l-6-6l-.083-.094l-.054-.077l-.054-.096l-.017-.036l-.027-.067l-.032-.108l-.01-.053l-.01-.06l-.004-.057v-.118l.005-.058l.009-.06l.01-.052l.032-.108l.027-.067l.07-.132l.065-.09l.073-.081l.094-.083l.077-.054l.096-.054l.036-.017l.067-.027l.108-.032l.053-.01l.06-.01l.057-.004z"></path></svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TablerCaretDownFilled'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
10
src/components/icons/TablerCaretUpFilled.vue
Normal file
10
src/components/icons/TablerCaretUpFilled.vue
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
<template>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="currentColor" d="M11.293 7.293a1 1 0 0 1 1.32-.083l.094.083l6 6l.083.094l.054.077l.054.096l.017.036l.027.067l.032.108l.01.053l.01.06l.004.057L19 14l-.002.059l-.005.058l-.009.06l-.01.052l-.032.108l-.027.067l-.07.132l-.065.09l-.073.081l-.094.083l-.077.054l-.096.054l-.036.017l-.067.027l-.108.032l-.053.01l-.06.01l-.057.004L18 15H6c-.852 0-1.297-.986-.783-1.623l.076-.084z"></path></svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TablerCaretUpFilled'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<PageContainer title="心率记录">
|
||||||
Charts
|
<div class="w-full h-full flex justify-center items-center bg-white">
|
||||||
|
<span class="text-sm font-semibold text-neutral-400">前面的区域,以后再来探索吧!</span>
|
||||||
</div>
|
</div>
|
||||||
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ onMounted(() => {
|
|||||||
<SvgSpinnersPulse2 class="icon text-5xl text-neutral-400" />
|
<SvgSpinnersPulse2 class="icon text-5xl text-neutral-400" />
|
||||||
<span class="text-sm font-semibold text-neutral-400">正在扫描蓝牙设备</span>
|
<span class="text-sm font-semibold text-neutral-400">正在扫描蓝牙设备</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="is_connecting"
|
<div v-else-if="is_connecting" class="w-full h-full flex flex-col gap-4 justify-center items-center">
|
||||||
class="w-full h-full flex flex-col gap-4 justify-center items-center">
|
|
||||||
<SvgSpinnersWifiFade class="icon text-5xl text-neutral-400" />
|
<SvgSpinnersWifiFade class="icon text-5xl text-neutral-400" />
|
||||||
<span class="text-sm font-semibold text-neutral-400">正在连接到设备</span>
|
<span class="text-sm font-semibold text-neutral-400">正在连接到设备</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<PageContainer title="设置">
|
||||||
Settings Page
|
<div class="w-full h-full flex justify-center items-center bg-white">
|
||||||
|
<span class="text-sm font-semibold text-neutral-400">前面的区域,以后再来探索吧!</span>
|
||||||
</div>
|
</div>
|
||||||
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<PageContainer title="推流插件">
|
||||||
Streaming Plugins
|
<div class="w-full h-full flex justify-center items-center bg-white">
|
||||||
|
<span class="text-sm font-semibold text-neutral-400">前面的区域,以后再来探索吧!</span>
|
||||||
</div>
|
</div>
|
||||||
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<PageContainer title="桌面组件">
|
||||||
Widgets Page
|
<div class="w-full h-full flex justify-center items-center bg-white">
|
||||||
|
<span class="text-sm font-semibold text-neutral-400">前面的区域,以后再来探索吧!</span>
|
||||||
</div>
|
</div>
|
||||||
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { ref, watchEffect } from "vue";
|
import { onMounted, ref, watchEffect } from "vue";
|
||||||
import { invoke } from "@tauri-apps/api/tauri";
|
import { invoke } from "@tauri-apps/api/tauri";
|
||||||
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import { useThrottleFn } from "@vueuse/core";
|
import { useThrottleFn } from "@vueuse/core";
|
||||||
|
|
||||||
export interface Device {
|
export interface Device {
|
||||||
@@ -17,6 +18,16 @@ export const useBrcatStore = defineStore("brcat", () => {
|
|||||||
|
|
||||||
const is_scanning = ref(false);
|
const is_scanning = ref(false);
|
||||||
|
|
||||||
|
const current_heart_rate = ref<Number>(0);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const unlisten = await listen("heart-rate", (heart_rate) => {
|
||||||
|
current_heart_rate.value = heart_rate.payload as Number;
|
||||||
|
});
|
||||||
|
|
||||||
|
return unlisten;
|
||||||
|
})
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
is_connected.value = await invoke("is_connected");
|
is_connected.value = await invoke("is_connected");
|
||||||
}, 500);
|
}, 500);
|
||||||
@@ -64,6 +75,7 @@ export const useBrcatStore = defineStore("brcat", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
current_heart_rate,
|
||||||
is_connected,
|
is_connected,
|
||||||
is_scanning,
|
is_scanning,
|
||||||
connected_device,
|
connected_device,
|
||||||
|
|||||||
@@ -4,6 +4,22 @@ export default <Config>{
|
|||||||
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
|
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: {
|
||||||
|
"50": "#fef1f6",
|
||||||
|
"100": "#fee5ef",
|
||||||
|
"200": "#ffcbe1",
|
||||||
|
"300": "#ffa1c6",
|
||||||
|
"400": "#ff6ea3",
|
||||||
|
"500": "#fa3a7b",
|
||||||
|
"600": "#ea1854",
|
||||||
|
"700": "#cc0a3c",
|
||||||
|
"800": "#a80c32",
|
||||||
|
"900": "#8c0f2d",
|
||||||
|
"950": "#560116",
|
||||||
|
DEFAULT: "#ff6ea3",
|
||||||
|
},
|
||||||
|
},
|
||||||
fontSize: {
|
fontSize: {
|
||||||
"2xs": [
|
"2xs": [
|
||||||
"0.625rem",
|
"0.625rem",
|
||||||
|
|||||||
Reference in New Issue
Block a user