feat(waybar): implement all dummy widgets

This commit is contained in:
Pihkaal
2024-07-31 15:13:53 +02:00
parent 1dcae0c20a
commit 0046e5dd82
28 changed files with 396 additions and 84 deletions

View File

@@ -1,51 +0,0 @@
import { WaybarWidgetGroup } from "./WaybarWidgetGroup";
import { WaybarCPUWidget } from "./Widgets/WaybarCPUWidget";
import { WaybarDiskWidget } from "./Widgets/WaybarDiskWidget";
import { WaybarRAMWidget } from "./Widgets/WaybarRAMWidget";
import { WaybarTitleWidget } from "./Widgets/WaybarTitleWidget";
export const Waybar = () => {
return (
<div className="flex w-full flex-row">
<WaybarWidgetGroup>
<WaybarCPUWidget variation={10} frequency={1000} cores={10} />
<WaybarRAMWidget
variation={0.5}
frequency={1000}
min={18}
max={25}
start={21}
capacity={16}
/>
<WaybarDiskWidget current={35.9} variation={4.1} capacity={160.3} />
</WaybarWidgetGroup>
<WaybarWidgetGroup>
<WaybarTitleWidget />
</WaybarWidgetGroup>
{/*
<WaybarWidgetGroup>
<WaybarLockWidget />
<WaybarTimeWidget />
<WaybarShutdownWidget />
</WaybarWidgetGroup>
<WaybarWidgetGroup>
<WaybarTemperatureWidget />
<WaybarBatteryWidget />
</WaybarWidgetGroup>
<WaybarWidgetGroup>
<WaybarBrightnessWidget />
<WaybarVolumeWidget />
<WaybarMicrophoneWidget />
</WaybarWidgetGroup>
<WaybarWidgetGroup>
<WaybarTrayWidget />
<WaybarWeatherWidget />
</WaybarWidgetGroup>
*/}
</div>
);
};

View File

@@ -4,9 +4,16 @@ import { cn } from "~/utils/react";
export const WaybarWidget = (props: {
className?: string;
tooltip?: string;
interactable?: boolean;
children: ReactNode | Array<ReactNode>;
}) => (
<div className={cn("font-bold text-[#2b2b2c] ", props.className)}>
<div
className={cn(
"py-[6.5px] font-bold text-[#2b2b2c]",
props.className,
props.interactable && "cursor-pointer",
)}
>
{props.children}
</div>
);

View File

@@ -1,9 +1,17 @@
import { type ReactNode } from "react";
import { cn } from "~/utils/react";
export const WaybarWidgetGroup = (props: {
className?: string;
children: ReactNode | Array<ReactNode>;
}) => (
<div className="flex flex-row justify-between gap-5 rounded-lg bg-[#e6e7ec] px-4 py-[5px] opacity-80">
<div
className={cn(
`flex flex-row justify-between rounded-[10px] bg-[#e6e7ec] opacity-80`,
props.className,
)}
>
{props.children}
</div>
);
// gap-5 px-3 py-[6.5px]

View File

@@ -0,0 +1,27 @@
import { useEffect, useState } from "react";
import { WaybarWidget } from "../WaybarWidget";
import { lerpIcon } from "~/utils/icons";
const ICONS = ["󰂎", "󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"];
export const WaybarBatteryWidget = (props: { frequency: number }) => {
const [battery, setBattery] = useState(100);
useEffect(() => {
const interval = setInterval(() => {
setBattery((x) => x - 1);
if (battery - 1 === 0) {
// TODO: do something
}
}, props.frequency);
return () => clearInterval(interval);
});
return (
<WaybarWidget className="pl-[0.625rem] pr-3 text-[#1d7715]">
{lerpIcon(ICONS, battery, 100)} {battery}%
</WaybarWidget>
);
};

View File

@@ -0,0 +1,26 @@
import { type WheelEvent } from "react";
import { clamp } from "~/utils/math";
import { WaybarWidget } from "../WaybarWidget";
import { useApp } from "~/hooks/useApp";
import { lerpIcon } from "~/utils/icons";
const ICONS = ["󰃞", "󰃟", "󰃠"];
export const WaybarBrightnessWidget = () => {
const { brightness, setBrightness } = useApp();
const handleScroll = (e: WheelEvent) => {
let newBrightness = brightness - Math.sign(e.deltaY);
newBrightness = clamp(newBrightness, 0, 100);
setBrightness(newBrightness);
};
return (
<WaybarWidget className="pl-3 pr-[0.625rem]">
<span onWheel={handleScroll}>
{lerpIcon(ICONS, brightness, 100)} {brightness}%
</span>
</WaybarWidget>
);
};

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useEffect, useState } from "react";
import { WaybarWidget } from "../WaybarWidget";
// 1 is really active, but often changes, 19-30%
@@ -11,10 +11,6 @@ export const WaybarCPUWidget = (props: {
frequency: number;
}) => {
const [usage, setUsage] = useState(new Array<number>(props.cores).fill(0));
const totalUsage = useMemo(
() => Math.round(usage.reduce((acc, v) => acc + v, 0) / usage.length),
[usage],
);
useEffect(() => {
const interval = setInterval(() => {
@@ -23,7 +19,13 @@ export const WaybarCPUWidget = (props: {
}, props.frequency);
return () => clearInterval(interval);
}, [usage]);
}, [usage, props.frequency]);
return <WaybarWidget> {totalUsage}%</WaybarWidget>;
const totalUsage = Math.round(
usage.reduce((acc, v) => acc + v, 0) / usage.length,
);
return (
<WaybarWidget className="pl-3 pr-[0.625rem]"> {totalUsage}%</WaybarWidget>
);
};

View File

@@ -12,5 +12,5 @@ export const WaybarDiskWidget = (props: {
props.current + randomMinMax(-props.variation, props.variation + 1);
const usage = Math.round((value / props.capacity) * 100);
return <WaybarWidget>󰋊 {usage}%</WaybarWidget>;
return <WaybarWidget className="pl-[0.625rem] pr-3">󰋊 {usage}%</WaybarWidget>;
};

View File

@@ -0,0 +1,5 @@
import { WaybarWidget } from "../WaybarWidget";
export const WaybarHomeWidget = () => (
<WaybarWidget className="text-[#407cdd]"></WaybarWidget>
);

View File

@@ -0,0 +1,9 @@
import { WaybarWidget } from "../WaybarWidget";
export const WaybarLockWidget = () => {
return (
<WaybarWidget className="pl-3 pr-[0.625rem]" interactable>
</WaybarWidget>
);
};

View File

@@ -0,0 +1,33 @@
import { type WheelEvent, useState } from "react";
import { clamp } from "~/utils/math";
import { WaybarWidget } from "../WaybarWidget";
export const WaybarMicrophoneWidget = () => {
const [muted, setMuted] = useState(false);
const [volume, setVolume] = useState(100);
const handleWheel = (e: WheelEvent) => {
let newVolume = volume - Math.sign(e.deltaY) * 5;
newVolume = clamp(newVolume, 0, 100);
setVolume(newVolume);
};
const handleClick = () => {
setMuted((muted) => !muted);
};
const icon = muted ? "" : "";
return (
<WaybarWidget className="pl-[0.625rem] pr-3" interactable>
<span
className="text-[#ad6bfd]"
onWheel={handleWheel}
onClick={handleClick}
>
{icon} {!muted && `${volume}%`}
</span>
</WaybarWidget>
);
};

View File

@@ -0,0 +1,9 @@
import { WaybarWidget } from "../WaybarWidget";
export const WaybarPowerWidget = () => {
return (
<WaybarWidget className="pl-[0.625rem] pr-3" interactable>
</WaybarWidget>
);
};

View File

@@ -26,5 +26,5 @@ export const WaybarRAMWidget = (props: {
// TODO: tooltip
// Memory - (capacity * usage).1f GB used
return <WaybarWidget> {usage}%</WaybarWidget>;
return <WaybarWidget className="px-[0.625rem]"> {usage}%</WaybarWidget>;
};

View File

@@ -1,9 +0,0 @@
import { WaybarWidget } from "./WaybarWidget";
export const WaybarSessionWidget = () => (
<WaybarWidget>
<span></span>
<span>03:13 PM</span>
<span></span>
</WaybarWidget>
);

View File

@@ -0,0 +1,29 @@
import { useEffect, useState } from "react";
import { WaybarWidget } from "../WaybarWidget";
import { clamp, randomMinMax } from "~/utils/math";
export const WaybarTemperatureWidget = (props: {
min: number;
max: number;
variation: number;
frequency: number;
}) => {
const [temperature, setTemperature] = useState(
randomMinMax(props.min, props.max),
);
useEffect(() => {
const interval = setInterval(() => {
const offset = randomMinMax(-props.variation, props.variation + 1);
setTemperature((x) => clamp(x + offset, props.min, props.max));
}, props.frequency);
return () => clearInterval(interval);
});
return (
<WaybarWidget className="pl-3 pr-[0.625rem]">
{temperature}°C
</WaybarWidget>
);
};

View File

@@ -0,0 +1,24 @@
import { useEffect, useState } from "react";
import { WaybarWidget } from "../WaybarWidget";
export const WaybarTimeWidget = () => {
const [date, setDate] = useState(new Date());
useEffect(() => {
const interval = setInterval(() => {
setDate(new Date());
}, 1000);
return () => {
clearInterval(interval);
};
});
const time = date.toLocaleString("en-US", {
hour: "2-digit",
minute: "2-digit",
hour12: true,
});
return <WaybarWidget className="px-[0.625rem]">{time}</WaybarWidget>;
};

View File

@@ -1,3 +1,5 @@
import { WaybarWidget } from "../WaybarWidget";
export const WaybarTitleWidget = () => <WaybarWidget>nvim</WaybarWidget>;
export const WaybarTitleWidget = () => (
<WaybarWidget className="px-3">nvim</WaybarWidget>
);

View File

@@ -0,0 +1,7 @@
import { WaybarWidget } from "../WaybarWidget";
export const WaybarToggleThemeWidget = () => (
<WaybarWidget className="pl-[0.625rem] pr-3" interactable>
󰐾
</WaybarWidget>
);

View File

@@ -0,0 +1,5 @@
import { WaybarWidget } from "../WaybarWidget";
export const WaybarTrayWidget = () => (
<WaybarWidget className="pl-3 pr-[0.625rem]">X</WaybarWidget>
);

View File

@@ -0,0 +1,37 @@
import { type WheelEvent, useState } from "react";
import { clamp } from "~/utils/math";
import { WaybarWidget } from "../WaybarWidget";
import { useApp } from "~/hooks/useApp";
import { lerpIcon } from "~/utils/icons";
const ICONS = ["", "", ""];
export const WaybarVolumeWidget = () => {
const [muted, setMuted] = useState(false);
const { volume, setVolume } = useApp();
const handleWheel = (e: WheelEvent) => {
let newVolume = volume - Math.sign(e.deltaY) * 5;
newVolume = clamp(newVolume, 0, 100);
setVolume(newVolume);
};
const handleClick = () => {
setMuted(!muted);
};
const icon = muted ? "" : lerpIcon(ICONS, volume, 100);
return (
<WaybarWidget className="px-[0.625rem]" interactable>
<span
className="text-[#407cdd]"
onWheel={handleWheel}
onClick={handleClick}
>
{icon} {!muted && `${volume}%`}
</span>
</WaybarWidget>
);
};

View File

@@ -0,0 +1,5 @@
import { WaybarWidget } from "../WaybarWidget";
export const WaybarWeatherWidget = () => (
<WaybarWidget className="px-[0.625rem]">🌧 27°</WaybarWidget>
);

View File

@@ -0,0 +1,78 @@
import { WaybarWidgetGroup } from "./WaybarWidgetGroup";
import { WaybarCPUWidget } from "./Widgets/WaybarCPUWidget";
import { WaybarDiskWidget } from "./Widgets/WaybarDiskWidget";
import { WaybarRAMWidget } from "./Widgets/WaybarRAMWidget";
import { WaybarTitleWidget } from "./Widgets/WaybarTitleWidget";
import { WaybarHomeWidget } from "./Widgets/WaybarHomeWidget";
import { randomMinMax } from "~/utils/math";
import { WaybarTemperatureWidget } from "./Widgets/WaybarTemperatureWidget";
import { WaybarBatteryWidget } from "./Widgets/WaybarBatteryWidget";
import { WaybarBrightnessWidget } from "./Widgets/WaybarBrightnessWidget";
import { WaybarVolumeWidget } from "./Widgets/WaybarVolumeWidget";
import { WaybarMicrophoneWidget } from "./Widgets/WaybarMicrophoneWidget";
import { WaybarLockWidget } from "./Widgets/WaybarLockWidget";
import { WaybarTimeWidget } from "./Widgets/WaybarTimeWidget";
import { WaybarPowerWidget } from "./Widgets/WaybarPowerWidget";
import { WaybarTrayWidget } from "./Widgets/WaybarTrayWidget";
import { WaybarToggleThemeWidget } from "./Widgets/WaybarToggleThemeWidget";
import { WaybarWeatherWidget } from "./Widgets/WaybarWeatherWidget";
export const Waybar = () => {
return (
<div className="grid h-[37px] w-full select-none grid-cols-[1fr_max-content_1fr] grid-rows-1 gap-0">
<div className="flex items-center gap-3">
<WaybarWidgetGroup className="rounded-r-[5px] pl-[10px] pr-[14px]">
<WaybarHomeWidget />
</WaybarWidgetGroup>
<WaybarWidgetGroup>
<WaybarCPUWidget variation={2} frequency={1000} cores={10} />
<WaybarRAMWidget
variation={1}
frequency={3000}
min={18}
max={40}
start={randomMinMax(20, 30)}
capacity={16}
/>
<WaybarDiskWidget current={35.9} variation={4.1} capacity={160.3} />
</WaybarWidgetGroup>
<WaybarWidgetGroup>
<WaybarTitleWidget />
</WaybarWidgetGroup>
</div>
<div className="flex items-center">
<WaybarWidgetGroup>
<WaybarLockWidget />
<WaybarTimeWidget />
<WaybarPowerWidget />
</WaybarWidgetGroup>
</div>
<div className="flex items-center justify-end gap-2">
<WaybarWidgetGroup>
<WaybarTemperatureWidget
min={50}
max={70}
variation={1}
frequency={7000}
/>
<WaybarBatteryWidget frequency={7000} />
</WaybarWidgetGroup>
<WaybarWidgetGroup>
<WaybarBrightnessWidget />
<WaybarVolumeWidget />
<WaybarMicrophoneWidget />
</WaybarWidgetGroup>
<WaybarWidgetGroup>
<WaybarTrayWidget />
<WaybarWeatherWidget />
<WaybarToggleThemeWidget />
</WaybarWidgetGroup>
</div>
</div>
);
};