complete Device List component.

This commit is contained in:
Vixalie 2025-02-28 16:24:16 +08:00
parent 044a17f569
commit 1630c0ea64
3 changed files with 91 additions and 16 deletions

View File

@ -56,24 +56,37 @@ export const DeviceState = atomWithRefresh<PeripheralItem | null>(async (get) =>
}
return null;
});
export const FoundPeripherals = atom(
[] as PeripheralItem[],
(get, set, item: PeripheralItem | typeof RESET) => {
const Peripherals = atom<PeripheralItem[]>([]);
export const FoundPeripherals = atom(null, (get, set, item: PeripheralItem | typeof RESET) => {
if (item === RESET) {
void set(FoundPeripherals, []);
void set(Peripherals, []);
} else {
void set(FoundPeripherals, (prev) => {
const foundIndex = prev.findIndex((i) => i.id === item.id);
if (foundIndex !== -1) {
prev[foundIndex] = item;
void set(Peripherals, (prev) => {
let replaced = false;
const newPeripherals = prev.map((i) => {
if (i.id === item.id) {
replaced = true;
return item;
} else {
prev.push(item);
return i;
}
return prev;
});
if (!replaced) {
newPeripherals.push(item);
}
return newPeripherals;
});
}
},
);
});
export const AvailablePeripherals = atom((get) => {
const peripherals = get(Peripherals);
return peripherals.filter((i) => !i.isUnknown);
});
export const UnknownPeripherals = atom((get) => {
const peripherals = get(Peripherals);
console.debug('[origin peripherals]', peripherals);
return peripherals.filter((i) => i.isUnknown);
});
const Channels: Record<Channels, PrimitiveAtom<ChannelState>> = {
a: atomWithRefresh<ChannelState>(async (get) => {
try {

View File

@ -5,4 +5,43 @@
flex-direction: column;
align-items: stretch;
}
.devices_list_layout {
padding-inline: calc(var(--spacing) * 2);
display: flex;
flex-direction: column;
align-items: stretch;
gap: calc(var(--spacing) * 4);
}
.devices_list {
display: flex;
flex-direction: column;
align-items: stretch;
gap: calc(var(--spacing) * 2);
.device_card {
padding-inline: calc(var(--spacing) * 2);
padding-block: calc(var(--spacing) * 3);
border-radius: calc(var(--border-radius) * 2);
background-color: var(--color-dark-surface);
color: var(--color-dark-on-surface);
display: flex;
flex-direction: row;
align-items: center;
gap: calc(var(--spacing) * 1);
.device_name {
flex: 1;
font-size: calc(var(--font-size) * 1.3);
overflow: hidden;
text-overflow: ellipsis;
}
&:hover {
background-color: color-mix(in oklch, var(--color-dark-on-surface) 8%, transparent);
}
}
.empty_prompt {
padding-block: calc(var(--spacing) * 1);
text-align: center;
font-size: calc(var(--font-size) * 0.8);
color: var(--color-dark-on-surface-variant);
}
}
}

View File

@ -1,11 +1,34 @@
import { useAtomValue } from 'jotai';
import { FC } from 'react';
import { ScrollArea } from '../../components/ScrollArea';
import { AvailablePeripherals } from '../../context/EstimContext';
import IconRssi from '../../icons/IconRssi';
import styles from './DeviceList.module.css';
const AvailableDevices: FC = () => {
const devices = useAtomValue(AvailablePeripherals);
return (
<div className={styles.devices_list}>
{devices.length === 0 && <div className={styles.empty_prompt}>No available devices.</div>}
{devices.map((device, index) => (
<div key={index} className={styles.device_card}>
<div className={styles.device_name}>{device.represent}</div>
<IconRssi height={14} level={device.rssi} />
</div>
))}
</div>
);
};
const DeviceList: FC = () => {
return (
<div className={styles.devices}>
<ScrollArea enableY></ScrollArea>
<ScrollArea enableY>
<div className={styles.devices_list_layout}>
<AvailableDevices />
</div>
</ScrollArea>
</div>
);
};