diff --git a/bun.lockb b/bun.lockb
index 60009f1..379f46c 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index 43213d1..48a7b26 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
},
"dependencies": {
"@tanstack/react-query": "^5.32.0",
+ "jotai": "^2.8.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
diff --git a/src/client/App.css b/src/client/App.css
index 53bf59d..fb0928e 100644
--- a/src/client/App.css
+++ b/src/client/App.css
@@ -10,7 +10,7 @@
background-color: var(--color-background0);
padding: 16px;
width: 100%;
- height: max-content;
+ min-height: max-content;
overflow: hidden;
}
@@ -20,18 +20,17 @@
@media (min-width: 640px) {
@media (min-height: 640px) {
- height: 100vh;
-
- > div {
- height: 100%;
- }
-
.chart {
min-height: unset;
}
@media (orientation: landscape) {
grid-template-columns: repeat(3, 1fr);
+ height: 100vh;
+
+ > div {
+ height: 100%;
+ }
}
@media (orientation: portrait) {
diff --git a/src/client/atoms/index.ts b/src/client/atoms/index.ts
new file mode 100644
index 0000000..f2686c7
--- /dev/null
+++ b/src/client/atoms/index.ts
@@ -0,0 +1,4 @@
+import { atom } from 'jotai';
+
+export const highFpsAtom = atom(true);
+export const siAtom = atom(false);
diff --git a/src/client/components/chart-cards/common/chart/index.tsx b/src/client/components/chart-cards/common/chart/index.tsx
index db967c5..a4d3c1e 100644
--- a/src/client/components/chart-cards/common/chart/index.tsx
+++ b/src/client/components/chart-cards/common/chart/index.tsx
@@ -8,7 +8,6 @@ import { YAxis } from './y-axis';
const stepWindow = Number(import.meta.env.CLIENT_GRAPH_STEPS);
const stepPeriod = Number(import.meta.env.CLIENT_REFETCH_INTERVAL);
const xMargin = 4;
-const fps = 30;
type Props = {
total: number;
@@ -33,7 +32,7 @@ export const CanvasChart = ({ total, hueOffset = 0, domain, hardDomain, data, fo
}
if (!domain || historyMax > domain[1]) {
- return 1.25 * historyMax;
+ return historyMax;
}
return domain[1];
@@ -129,7 +128,7 @@ export const CanvasChart = ({ total, hueOffset = 0, domain, hardDomain, data, fo
drawSeries('fill');
drawSeries('stroke');
- }, fps);
+ });
return (
diff --git a/src/client/components/chart-cards/disks.tsx b/src/client/components/chart-cards/disks.tsx
index 1469ed0..cf3dfd3 100644
--- a/src/client/components/chart-cards/disks.tsx
+++ b/src/client/components/chart-cards/disks.tsx
@@ -1,8 +1,11 @@
+import { siAtom } from '@/atoms';
import { useQuery } from '@tanstack/react-query';
+import { useAtomValue } from 'jotai';
import { ChartCard } from './common/card';
export const Disks = () => {
const { data: dynamicData } = useQuery
({ queryKey: ['dynamic'] });
+ const isSi = useAtomValue(siAtom);
if (!dynamicData) {
return ;
@@ -15,7 +18,7 @@ export const Disks = () => {
labels: ['Read', 'Write'],
}}
hueOffset={120}
- formatOptions={{ units: 'B/s' }}
+ formatOptions={{ units: 'B/s', ...(isSi && { si: true }) }}
data={[dynamicData.disks.read, dynamicData.disks.write]}
total={2}
/>
diff --git a/src/client/components/chart-cards/memory.tsx b/src/client/components/chart-cards/memory.tsx
index ed3e48b..967f2b5 100644
--- a/src/client/components/chart-cards/memory.tsx
+++ b/src/client/components/chart-cards/memory.tsx
@@ -1,20 +1,22 @@
+import { siAtom } from '@/atoms';
import { formatValue } from '@/utils/format';
import { useQuery } from '@tanstack/react-query';
+import { useAtomValue } from 'jotai';
import { useMemo } from 'react';
import { ChartCard } from './common/card';
-const formatOptions = { units: 'B' };
-
export const Memory = () => {
const { data: staticData } = useQuery({ queryKey: ['static'] });
const { data: dynamicData } = useQuery({ queryKey: ['dynamic'] });
+ const isSi = useAtomValue(siAtom);
+ const formatOptions = { units: 'B', ...(isSi && { si: true }) };
const formatedTotals = useMemo(() => {
if (!staticData) {
return [];
}
return [formatValue(staticData.total_memory, formatOptions), formatValue(staticData.total_swap, formatOptions)];
- }, [staticData]);
+ }, [staticData, formatOptions]);
if (!staticData || !dynamicData) {
return ;
diff --git a/src/client/components/chart-cards/network.tsx b/src/client/components/chart-cards/network.tsx
index 349802a..566653b 100644
--- a/src/client/components/chart-cards/network.tsx
+++ b/src/client/components/chart-cards/network.tsx
@@ -1,8 +1,11 @@
+import { siAtom } from '@/atoms';
import { useQuery } from '@tanstack/react-query';
+import { useAtomValue } from 'jotai';
import { ChartCard } from './common/card';
export const Network = () => {
const { data: dynamicData } = useQuery({ queryKey: ['dynamic'] });
+ const isSi = useAtomValue(siAtom);
if (!dynamicData) {
return ;
@@ -15,7 +18,7 @@ export const Network = () => {
labels: ['Down', 'Up'],
}}
hueOffset={60}
- formatOptions={{ units: 'B/s' }}
+ formatOptions={{ units: 'B/s', ...(isSi && { si: true }) }}
data={[dynamicData.network.down, dynamicData.network.up]}
total={2}
/>
diff --git a/src/client/components/chart-cards/static.css b/src/client/components/chart-cards/static.css
new file mode 100644
index 0000000..63e9ec4
--- /dev/null
+++ b/src/client/components/chart-cards/static.css
@@ -0,0 +1,7 @@
+.switches {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: wrap;
+ gap: 8px;
+ padding: 4px 0px;
+}
\ No newline at end of file
diff --git a/src/client/components/chart-cards/static.tsx b/src/client/components/chart-cards/static.tsx
index 20e5b15..f3737c8 100644
--- a/src/client/components/chart-cards/static.tsx
+++ b/src/client/components/chart-cards/static.tsx
@@ -1,7 +1,10 @@
+import { highFpsAtom, siAtom } from '@/atoms';
+import { Switch } from '@/components/switch';
import { useAnimationFrame } from '@/hooks/use-animation-frame';
import { useQuery } from '@tanstack/react-query';
+import { useAtom } from 'jotai';
import { useEffect, useRef, useState } from 'react';
-import { Switch } from '../switch';
+import './static.css';
const formatUptime = (value: number) => {
const seconds = String(Math.floor(value % 60)).padStart(2, '0');
@@ -40,6 +43,8 @@ export const Static = () => {
const { data: staticData } = useQuery({ queryKey: ['static'] });
const root = useRef(document.getElementById('root')!);
const [dark, setDark] = useState(window.matchMedia('(prefers-color-scheme: dark)').matches);
+ const [highFps, setHighFps] = useAtom(highFpsAtom);
+ const [isSi, setIsSi] = useAtom(siAtom);
useEffect(() => {
root.current.setAttribute('data-theme', dark ? 'dark' : 'light');
@@ -59,11 +64,25 @@ export const Static = () => {
{staticData.kernel_version}
{staticData.boot_time && }
- setDark(target.checked)}
- />
+
+ setDark(target.checked)}
+ />
+
+ setHighFps(target.checked)}
+ />
+
+ setIsSi(target.checked)}
+ />
+
)
);
diff --git a/src/client/hooks/use-animation-frame.ts b/src/client/hooks/use-animation-frame.ts
index 97957a6..ea06899 100644
--- a/src/client/hooks/use-animation-frame.ts
+++ b/src/client/hooks/use-animation-frame.ts
@@ -1,9 +1,13 @@
+import { highFpsAtom } from '@/atoms';
+import { useAtomValue } from 'jotai';
import { useEffect, useRef } from 'react';
-export const useAnimationFrame = (callback: (dt: number) => void, fps = 60) => {
+export const useAnimationFrame = (callback: (dt: number) => void, fps?: number) => {
const ignored = useRef(0);
const requestRef = useRef();
const previousTimeRef = useRef();
+ const highFps = useAtomValue(highFpsAtom);
+ const autoFps = fps ?? (highFps ? 30 : 4);
useEffect(() => {
const animate: FrameRequestCallback = time => {
@@ -11,7 +15,7 @@ export const useAnimationFrame = (callback: (dt: number) => void, fps = 60) => {
const deltaTime = time - previousTimeRef.current;
ignored.current += deltaTime;
- if (ignored.current > 1000 / fps) {
+ if (ignored.current > 1000 / autoFps) {
ignored.current = 0;
callback(deltaTime);
}
@@ -26,5 +30,5 @@ export const useAnimationFrame = (callback: (dt: number) => void, fps = 60) => {
cancelAnimationFrame(requestRef.current);
}
};
- }, [callback, fps]);
+ }, [callback, autoFps]);
};