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; return null;
}); });
export const FoundPeripherals = atom( const Peripherals = atom<PeripheralItem[]>([]);
[] as PeripheralItem[], export const FoundPeripherals = atom(null, (get, set, item: PeripheralItem | typeof RESET) => {
(get, set, item: PeripheralItem | typeof RESET) => { if (item === RESET) {
if (item === RESET) { void set(Peripherals, []);
void set(FoundPeripherals, []); } else {
} else { void set(Peripherals, (prev) => {
void set(FoundPeripherals, (prev) => { let replaced = false;
const foundIndex = prev.findIndex((i) => i.id === item.id); const newPeripherals = prev.map((i) => {
if (foundIndex !== -1) { if (i.id === item.id) {
prev[foundIndex] = item; replaced = true;
return item;
} else { } 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>> = { const Channels: Record<Channels, PrimitiveAtom<ChannelState>> = {
a: atomWithRefresh<ChannelState>(async (get) => { a: atomWithRefresh<ChannelState>(async (get) => {
try { try {

View File

@ -5,4 +5,43 @@
flex-direction: column; flex-direction: column;
align-items: stretch; 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 { FC } from 'react';
import { ScrollArea } from '../../components/ScrollArea'; import { ScrollArea } from '../../components/ScrollArea';
import { AvailablePeripherals } from '../../context/EstimContext';
import IconRssi from '../../icons/IconRssi';
import styles from './DeviceList.module.css'; 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 = () => { const DeviceList: FC = () => {
return ( return (
<div className={styles.devices}> <div className={styles.devices}>
<ScrollArea enableY></ScrollArea> <ScrollArea enableY>
<div className={styles.devices_list_layout}>
<AvailableDevices />
</div>
</ScrollArea>
</div> </div>
); );
}; };