feat: define bar layout via config

This commit is contained in:
2 * r + 2 * t 2025-04-02 22:12:06 +11:00
parent 473e5a6b8a
commit 579070733c
5 changed files with 172 additions and 136 deletions

View file

@ -280,7 +280,7 @@
margin-right: -1px; margin-right: -1px;
} }
.power { .last {
padding-right: lib.s(12); padding-right: lib.s(12);
} }
} }
@ -304,11 +304,11 @@
margin-bottom: -1px; margin-bottom: -1px;
} }
.os-icon { .first {
padding-top: lib.s(12); padding-top: lib.s(12);
} }
.power { .last {
padding-bottom: lib.s(12); padding-bottom: lib.s(12);
} }
} }

View file

@ -10,43 +10,44 @@ export default {
bar: { bar: {
vertical: true, vertical: true,
style: "gaps", // One of "gaps", "panel", "embedded" style: "gaps", // One of "gaps", "panel", "embedded"
layout: {
type: "centerbox", // One of "centerbox", "flowbox"
centerbox: {
start: ["osIcon", "activeWindow", "mediaPlaying", "brightnessSpacer"],
center: ["workspaces"],
end: [
"volumeSpacer",
"tray",
"statusIcons",
"pkgUpdates",
"notifCount",
"battery",
"dateTime",
"power",
],
},
flowbox: [
"osIcon",
"workspaces",
"brightnessSpacer",
"activeWindow",
"volumeSpacer",
"dateTime",
"tray",
"battery",
"statusIcons",
"notifCount",
"power",
],
},
modules: { modules: {
osIcon: {
enabled: true,
},
activeWindow: {
enabled: true,
},
mediaPlaying: {
enabled: true,
},
workspaces: { workspaces: {
enabled: true,
shown: 5, shown: 5,
}, },
tray: {
enabled: true,
},
statusIcons: {
enabled: true,
},
pkgUpdates: {
enabled: true,
},
notifCount: {
enabled: true,
},
battery: {
enabled: true,
},
dateTime: { dateTime: {
enabled: true,
format: "%d/%m/%y %R", format: "%d/%m/%y %R",
detailedFormat: "%c", detailedFormat: "%c",
}, },
power: {
enabled: true,
},
}, },
}, },
launcher: { launcher: {

View file

@ -25,6 +25,9 @@ const isCorrectType = (v: any, type: string | string[] | number[], path: string)
try { try {
// Recursively check type // Recursively check type
const type = JSON.parse(arrType); const type = JSON.parse(arrType);
if (Array.isArray(type)) {
v.splice(0, v.length, ...v.filter((item, i) => isCorrectType(item, type, `${path}[${i}]`)));
} else {
const valid = v.filter((item, i) => const valid = v.filter((item, i) =>
Object.entries(type).some(([k, t]) => { Object.entries(type).some(([k, t]) => {
if (!item[k]) { if (!item[k]) {
@ -35,6 +38,7 @@ const isCorrectType = (v: any, type: string | string[] | number[], path: string)
}) })
); );
v.splice(0, v.length, ...valid); // In-place filter v.splice(0, v.length, ...valid); // In-place filter
}
} catch { } catch {
const valid = v.filter((item, i) => { const valid = v.filter((item, i) => {
if (typeof item !== arrType) { if (typeof item !== arrType) {

View file

@ -1,9 +1,25 @@
const BOOL = "boolean"; const BOOL = "boolean";
const STR = "string"; const STR = "string";
const NUM = "number"; const NUM = "number";
const ARR = (type: string) => `array of ${type}`; const ARR = (type: string | string[]) => `array of ${typeof type === "string" ? type : JSON.stringify(type)}`;
const OBJ_ARR = (shape: object) => ARR(JSON.stringify(shape)); const OBJ_ARR = (shape: object) => ARR(JSON.stringify(shape));
const barModules = [
"osIcon",
"activeWindow",
"mediaPlaying",
"brightnessSpacer",
"workspaces",
"volumeSpacer",
"tray",
"statusIcons",
"pkgUpdates",
"notifCount",
"battery",
"dateTime",
"power",
];
export default { export default {
"style.transparency": ["off", "normal", "high"], "style.transparency": ["off", "normal", "high"],
"style.borders": BOOL, "style.borders": BOOL,
@ -11,20 +27,14 @@ export default {
// Bar // Bar
"bar.vertical": BOOL, "bar.vertical": BOOL,
"bar.style": ["gaps", "panel", "embedded"], "bar.style": ["gaps", "panel", "embedded"],
"bar.modules.osIcon.enabled": BOOL, "bar.layout.type": ["centerbox", "flowbox"],
"bar.modules.activeWindow.enabled": BOOL, "bar.layout.centerbox.start": ARR(barModules),
"bar.modules.mediaPlaying.enabled": BOOL, "bar.layout.centerbox.center": ARR(barModules),
"bar.modules.workspaces.enabled": BOOL, "bar.layout.centerbox.end": ARR(barModules),
"bar.layout.flowbox": ARR(barModules),
"bar.modules.workspaces.shown": NUM, "bar.modules.workspaces.shown": NUM,
"bar.modules.tray.enabled": BOOL,
"bar.modules.statusIcons.enabled": BOOL,
"bar.modules.pkgUpdates.enabled": BOOL,
"bar.modules.notifCount.enabled": BOOL,
"bar.modules.battery.enabled": BOOL,
"bar.modules.dateTime.enabled": BOOL,
"bar.modules.dateTime.format": STR, "bar.modules.dateTime.format": STR,
"bar.modules.dateTime.detailedFormat": STR, "bar.modules.dateTime.detailedFormat": STR,
"bar.modules.power.enabled": BOOL,
// Launcher // Launcher
"launcher.style": ["lines", "round"], "launcher.style": ["lines", "round"],
"launcher.actionPrefix": STR, "launcher.actionPrefix": STR,

View file

@ -10,7 +10,7 @@ import { setupCustomTooltip } from "@/utils/widgets";
import ScreenCorner from "@/widgets/screencorner"; import ScreenCorner from "@/widgets/screencorner";
import { execAsync, Variable } from "astal"; import { execAsync, Variable } from "astal";
import { bind, kebabify } from "astal/binding"; import { bind, kebabify } from "astal/binding";
import { App, Astal, Gtk, type Widget } from "astal/gtk3"; import { App, Astal, Gtk, Widget } from "astal/gtk3";
import { bar as config } from "config"; import { bar as config } from "config";
import AstalBattery from "gi://AstalBattery"; import AstalBattery from "gi://AstalBattery";
import AstalBluetooth from "gi://AstalBluetooth"; import AstalBluetooth from "gi://AstalBluetooth";
@ -20,12 +20,14 @@ import AstalNotifd from "gi://AstalNotifd";
import AstalTray from "gi://AstalTray"; import AstalTray from "gi://AstalTray";
import AstalWp from "gi://AstalWp"; import AstalWp from "gi://AstalWp";
interface SpacerClassNameProps { interface ClassNameProps {
beforeSpacer?: boolean; beforeSpacer: boolean;
afterSpacer?: boolean; afterSpacer: boolean;
first: boolean;
last: boolean;
} }
interface ModuleProps extends SpacerClassNameProps { interface ModuleProps extends ClassNameProps {
monitor: Monitor; monitor: Monitor;
} }
@ -83,13 +85,33 @@ const switchPane = (monitor: Monitor, name: string) => {
} }
}; };
const spacerClassName = ({ beforeSpacer, afterSpacer }: SpacerClassNameProps) => const getClassName = ({ beforeSpacer, afterSpacer, first, last }: ClassNameProps) =>
`${beforeSpacer ? "before-spacer" : ""} ${afterSpacer ? "after-spacer" : ""}`; `${beforeSpacer ? "before-spacer" : ""} ${afterSpacer ? "after-spacer" : ""}` +
` ${first ? "first" : ""} ${last ? "last" : ""}`;
const getModule = (module: string) => {
module = module.toLowerCase();
if (module === "osicon") return OSIcon;
if (module === "activewindow") return ActiveWindow;
if (module === "mediaplaying") return MediaPlaying;
if (module === "workspaces") return Workspaces;
if (module === "tray") return Tray;
if (module === "statusicons") return StatusIcons;
if (module === "pkgupdates") return PkgUpdates;
if (module === "notifcount") return NotifCount;
if (module === "battery") return Battery;
if (module === "datetime") return DateTime;
if (module === "power") return Power;
if (module === "brightnessspacer") return BrightnessSpacer;
if (module === "volumespacer") return VolumeSpacer;
return () => null;
};
const isSpacer = (module?: string) => module?.toLowerCase().endsWith("spacer") ?? false;
const OSIcon = ({ monitor, ...props }: ModuleProps) => ( const OSIcon = ({ monitor, ...props }: ModuleProps) => (
<button <button
visible={bind(config.modules.osIcon.enabled)} className={`module os-icon ${getClassName(props)}`}
className={`module os-icon ${spacerClassName(props)}`}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "dashboard")} onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "dashboard")}
> >
{osIcon} {osIcon}
@ -98,9 +120,8 @@ const OSIcon = ({ monitor, ...props }: ModuleProps) => (
const ActiveWindow = ({ monitor, ...props }: ModuleProps) => ( const ActiveWindow = ({ monitor, ...props }: ModuleProps) => (
<box <box
visible={bind(config.modules.activeWindow.enabled)}
vertical={bind(config.vertical)} vertical={bind(config.vertical)}
className={`module active-window ${spacerClassName(props)}`} className={`module active-window ${getClassName(props)}`}
setup={self => { setup={self => {
const title = Variable(""); const title = Variable("");
const updateTooltip = (c: AstalHyprland.Client | null) => const updateTooltip = (c: AstalHyprland.Client | null) =>
@ -144,7 +165,6 @@ const MediaPlaying = ({ monitor, ...props }: ModuleProps) => {
players.lastPlayer ? `${players.lastPlayer.title} - ${players.lastPlayer.artist}` : fallback; players.lastPlayer ? `${players.lastPlayer.title} - ${players.lastPlayer.artist}` : fallback;
return ( return (
<button <button
visible={bind(config.modules.mediaPlaying.enabled)}
onClick={(_, event) => { onClick={(_, event) => {
if (event.button === Astal.MouseButton.PRIMARY) switchPane(monitor, "audio"); if (event.button === Astal.MouseButton.PRIMARY) switchPane(monitor, "audio");
else if (event.button === Astal.MouseButton.SECONDARY) players.lastPlayer?.play_pause(); else if (event.button === Astal.MouseButton.SECONDARY) players.lastPlayer?.play_pause();
@ -156,7 +176,7 @@ const MediaPlaying = ({ monitor, ...props }: ModuleProps) => {
setupCustomTooltip(self, bind(label)); setupCustomTooltip(self, bind(label));
}} }}
> >
<box vertical={bind(config.vertical)} className={`module media-playing ${spacerClassName(props)}`}> <box vertical={bind(config.vertical)} className={`module media-playing ${getClassName(props)}`}>
<icon <icon
setup={self => setup={self =>
players.hookLastPlayer(self, "notify::identity", () => { players.hookLastPlayer(self, "notify::identity", () => {
@ -228,7 +248,6 @@ const Workspace = ({ idx }: { idx: number }) => {
const Workspaces = ({ monitor, ...props }: ModuleProps) => ( const Workspaces = ({ monitor, ...props }: ModuleProps) => (
<eventbox <eventbox
visible={bind(config.modules.workspaces.enabled)}
onScroll={(_, event) => { onScroll={(_, event) => {
const activeWs = hyprland.focusedClient?.workspace.name; const activeWs = hyprland.focusedClient?.workspace.name;
if (activeWs?.startsWith("special:")) hyprland.dispatch("togglespecialworkspace", activeWs.slice(8)); if (activeWs?.startsWith("special:")) hyprland.dispatch("togglespecialworkspace", activeWs.slice(8));
@ -236,7 +255,7 @@ const Workspaces = ({ monitor, ...props }: ModuleProps) => (
hyprland.dispatch("workspace", (event.delta_y < 0 ? "-" : "+") + 1); hyprland.dispatch("workspace", (event.delta_y < 0 ? "-" : "+") + 1);
}} }}
> >
<box vertical={bind(config.vertical)} className={`module workspaces ${spacerClassName(props)}`}> <box vertical={bind(config.vertical)} className={`module workspaces ${getClassName(props)}`}>
{bind(config.modules.workspaces.shown).as( {bind(config.modules.workspaces.shown).as(
n => Array.from({ length: n }).map((_, idx) => <Workspace idx={idx + 1} />) // Start from 1 n => Array.from({ length: n }).map((_, idx) => <Workspace idx={idx + 1} />) // Start from 1
)} )}
@ -257,25 +276,17 @@ const TrayItem = (item: AstalTray.TrayItem) => (
</menubutton> </menubutton>
); );
const Tray = ({ monitor, ...props }: ModuleProps) => { const Tray = ({ monitor, ...props }: ModuleProps) => (
const visible = Variable.derive(
[config.modules.tray.enabled, bind(AstalTray.get_default(), "items")],
(e, i) => e && i.length > 0
);
return (
<box <box
visible={bind(visible)} visible={bind(AstalTray.get_default(), "items").as(i => i.length > 0)}
vertical={bind(config.vertical)} vertical={bind(config.vertical)}
className={`module tray ${spacerClassName(props)}`} className={`module tray ${getClassName(props)}`}
onDestroy={() => visible.drop()}
> >
{bind(AstalTray.get_default(), "items").as(i => i.map(TrayItem))} {bind(AstalTray.get_default(), "items").as(i => i.map(TrayItem))}
</box> </box>
); );
};
const Network = () => ( const Network = ({ monitor }: { monitor: Monitor }) => (
<button <button
onClick={(_, event) => { onClick={(_, event) => {
const network = AstalNetwork.get_default(); const network = AstalNetwork.get_default();
@ -378,7 +389,7 @@ const Network = () => (
</button> </button>
); );
const BluetoothDevice = (device: AstalBluetooth.Device) => ( const BluetoothDevice = ({ monitor, device }: { monitor: Monitor; device: AstalBluetooth.Device }) => (
<button <button
visible={bind(device, "connected")} visible={bind(device, "connected")}
onClick={(_, event) => { onClick={(_, event) => {
@ -398,7 +409,7 @@ const BluetoothDevice = (device: AstalBluetooth.Device) => (
</button> </button>
); );
const Bluetooth = () => ( const Bluetooth = ({ monitor }: { monitor: Monitor }) => (
<box vertical={bind(config.vertical)} className="bluetooth"> <box vertical={bind(config.vertical)} className="bluetooth">
<button <button
onClick={(_, event) => { onClick={(_, event) => {
@ -440,24 +451,21 @@ const Bluetooth = () => (
<label className="icon" label="bluetooth_disabled" name="disabled" /> <label className="icon" label="bluetooth_disabled" name="disabled" />
</stack> </stack>
</button> </button>
{bind(AstalBluetooth.get_default(), "devices").as(d => d.map(BluetoothDevice))} {bind(AstalBluetooth.get_default(), "devices").as(d =>
d.map(d => <BluetoothDevice monitor={monitor} device={d} />)
)}
</box> </box>
); );
const StatusIcons = ({ monitor, ...props }: ModuleProps) => ( const StatusIcons = ({ monitor, ...props }: ModuleProps) => (
<box <box vertical={bind(config.vertical)} className={`module status-icons ${getClassName(props)}`}>
visible={bind(config.modules.statusIcons.enabled)} <Network monitor={monitor} />
vertical={bind(config.vertical)} <Bluetooth monitor={monitor} />
className={`module status-icons ${spacerClassName(props)}`}
>
<Network />
<Bluetooth />
</box> </box>
); );
const PkgUpdates = ({ monitor, ...props }: ModuleProps) => ( const PkgUpdates = ({ monitor, ...props }: ModuleProps) => (
<button <button
visible={bind(config.modules.pkgUpdates.enabled)}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "packages")} onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "packages")}
setup={self => setup={self =>
setupCustomTooltip( setupCustomTooltip(
@ -466,7 +474,7 @@ const PkgUpdates = ({ monitor, ...props }: ModuleProps) => (
) )
} }
> >
<box vertical={bind(config.vertical)} className={`module pkg-updates ${spacerClassName(props)}`}> <box vertical={bind(config.vertical)} className={`module pkg-updates ${getClassName(props)}`}>
<label className="icon" label="download" /> <label className="icon" label="download" />
<label label={bind(Updates.get_default(), "numUpdates").as(String)} /> <label label={bind(Updates.get_default(), "numUpdates").as(String)} />
</box> </box>
@ -475,7 +483,6 @@ const PkgUpdates = ({ monitor, ...props }: ModuleProps) => (
const NotifCount = ({ monitor, ...props }: ModuleProps) => ( const NotifCount = ({ monitor, ...props }: ModuleProps) => (
<button <button
visible={bind(config.modules.notifCount.enabled)}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "notifpane")} onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "notifpane")}
setup={self => setup={self =>
setupCustomTooltip( setupCustomTooltip(
@ -486,7 +493,7 @@ const NotifCount = ({ monitor, ...props }: ModuleProps) => (
) )
} }
> >
<box vertical={bind(config.vertical)} className={`module notif-count ${spacerClassName(props)}`}> <box vertical={bind(config.vertical)} className={`module notif-count ${getClassName(props)}`}>
<label <label
className="icon" className="icon"
label={bind(AstalNotifd.get_default(), "dontDisturb").as(d => (d ? "notifications_off" : "info"))} label={bind(AstalNotifd.get_default(), "dontDisturb").as(d => (d ? "notifications_off" : "info"))}
@ -505,13 +512,9 @@ const NotifCount = ({ monitor, ...props }: ModuleProps) => (
); );
const Battery = ({ monitor, ...props }: ModuleProps) => { const Battery = ({ monitor, ...props }: ModuleProps) => {
const visible = Variable.derive(
[config.modules.battery.enabled, bind(AstalBattery.get_default(), "isBattery")],
(e, i) => e && i
);
const className = Variable.derive( const className = Variable.derive(
[bind(AstalBattery.get_default(), "percentage"), bind(AstalBattery.get_default(), "charging")], [bind(AstalBattery.get_default(), "percentage"), bind(AstalBattery.get_default(), "charging")],
(p, c) => `module battery ${c ? "charging" : p < 0.2 ? "low" : ""} ${spacerClassName(props)}` (p, c) => `module battery ${c ? "charging" : p < 0.2 ? "low" : ""} ${getClassName(props)}`
); );
const tooltip = Variable.derive( const tooltip = Variable.derive(
[bind(AstalBattery.get_default(), "timeToEmpty"), bind(AstalBattery.get_default(), "timeToFull")], [bind(AstalBattery.get_default(), "timeToEmpty"), bind(AstalBattery.get_default(), "timeToFull")],
@ -520,12 +523,11 @@ const Battery = ({ monitor, ...props }: ModuleProps) => {
return ( return (
<box <box
visible={bind(visible)} visible={bind(AstalBattery.get_default(), "isBattery")}
vertical={bind(config.vertical)} vertical={bind(config.vertical)}
className={bind(className)} className={bind(className)}
setup={self => setupCustomTooltip(self, bind(tooltip))} setup={self => setupCustomTooltip(self, bind(tooltip))}
onDestroy={() => { onDestroy={() => {
visible.drop();
className.drop(); className.drop();
tooltip.drop(); tooltip.drop();
}} }}
@ -536,8 +538,8 @@ const Battery = ({ monitor, ...props }: ModuleProps) => {
); );
}; };
const DateTimeHoriz = (props: SpacerClassNameProps) => ( const DateTimeHoriz = (props: ClassNameProps) => (
<box className={`module date-time ${spacerClassName(props)}`}> <box className={`module date-time ${getClassName(props)}`}>
<label className="icon" label="calendar_month" /> <label className="icon" label="calendar_month" />
<label <label
setup={self => { setup={self => {
@ -549,8 +551,8 @@ const DateTimeHoriz = (props: SpacerClassNameProps) => (
</box> </box>
); );
const DateTimeVertical = (props: SpacerClassNameProps) => ( const DateTimeVertical = (props: ClassNameProps) => (
<box vertical className={`module date-time ${spacerClassName(props)}`}> <box vertical className={`module date-time ${getClassName(props)}`}>
<label className="icon" label="calendar_month" /> <label className="icon" label="calendar_month" />
<label label={bindCurrentTime("%H")} /> <label label={bindCurrentTime("%H")} />
<label label={bindCurrentTime("%M")} /> <label label={bindCurrentTime("%M")} />
@ -559,7 +561,6 @@ const DateTimeVertical = (props: SpacerClassNameProps) => (
const DateTime = ({ monitor, ...props }: ModuleProps) => ( const DateTime = ({ monitor, ...props }: ModuleProps) => (
<button <button
visible={bind(config.modules.dateTime.enabled)}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "time")} onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "time")}
setup={self => setup={self =>
setupCustomTooltip(self, bindCurrentTime(bind(config.modules.dateTime.detailedFormat), undefined, self)) setupCustomTooltip(self, bindCurrentTime(bind(config.modules.dateTime.detailedFormat), undefined, self))
@ -571,8 +572,7 @@ const DateTime = ({ monitor, ...props }: ModuleProps) => (
const Power = ({ monitor, ...props }: ModuleProps) => ( const Power = ({ monitor, ...props }: ModuleProps) => (
<button <button
visible={bind(config.modules.power.enabled)} className={`module power ${getClassName(props)}`}
className={`module power ${spacerClassName(props)}`}
label="power_settings_new" label="power_settings_new"
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && App.toggle_window("session")} onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && App.toggle_window("session")}
/> />
@ -604,32 +604,51 @@ const VolumeSpacer = () => (
/> />
); );
const Bar = ({ monitor }: { monitor: Monitor }) => { const Bar = ({ monitor, layout }: { monitor: Monitor; layout: string }) => {
const className = Variable.derive( const className = Variable.derive(
[bind(config.vertical), bind(config.style)], [bind(config.vertical), bind(config.style)],
(v, s) => `bar ${v ? "vertical" : " horizontal"} ${s}` (v, s) => `bar ${v ? "vertical" : " horizontal"} ${s}`
); );
const modules =
layout === "centerbox"
? Variable.derive(Object.values(config.layout.centerbox))
: bind(config.layout.flowbox).as(m => [m]);
const Layout = layout === "centerbox" ? Widget.CenterBox : Widget.Box;
return ( return (
<centerbox vertical={bind(config.vertical)} className={bind(className)} onDestroy={() => className.drop()}> <Layout
vertical={bind(config.vertical)}
className={bind(className)}
onDestroy={() => {
className.drop();
if (modules instanceof Variable) modules.drop();
}}
>
{bind(modules).as(modules =>
modules.map((m, i) => (
<box vertical={bind(config.vertical)}> <box vertical={bind(config.vertical)}>
<OSIcon monitor={monitor} /> {m.map((n, j) => {
<ActiveWindow monitor={monitor} /> let beforeSpacer = false;
<MediaPlaying monitor={monitor} beforeSpacer /> if (j < m.length - 1) beforeSpacer = isSpacer(m[j + 1]);
<BrightnessSpacer monitor={monitor} /> else if (i < modules.length - 1) beforeSpacer = isSpacer(modules[i + 1][0]);
let afterSpacer = false;
if (j > 0) afterSpacer = isSpacer(m[j - 1]);
else if (i > 0) afterSpacer = isSpacer(modules[i - 1].at(-1));
const M = getModule(n);
return (
<M
monitor={monitor}
beforeSpacer={beforeSpacer}
afterSpacer={afterSpacer}
first={i === 0 && j === 0}
last={i === modules.length - 1 && j === m.length - 1}
/>
);
})}
</box> </box>
<Workspaces monitor={monitor} beforeSpacer afterSpacer /> ))
<box vertical={bind(config.vertical)}> )}
<VolumeSpacer /> </Layout>
<Tray monitor={monitor} afterSpacer />
<StatusIcons monitor={monitor} />
<PkgUpdates monitor={monitor} />
<NotifCount monitor={monitor} />
<Battery monitor={monitor} />
<DateTime monitor={monitor} />
<Power monitor={monitor} />
</box>
</centerbox>
); );
}; };
@ -657,7 +676,9 @@ export default ({ monitor }: { monitor: Monitor }) => (
/>, />,
]} ]}
> >
<Bar monitor={monitor} /> {bind(config.layout.type).as(l => (
<Bar monitor={monitor} layout={l} />
))}
</overlay> </overlay>
</window> </window>
); );