From 2908ff7dd6604ccd8335fe885ea54bcb7dd56c87 Mon Sep 17 00:00:00 2001 From: Jas Singh Date: Sat, 24 Aug 2024 00:01:21 -0700 Subject: [PATCH] Added 3 new styles for bar buttons. (#168) * Added a new style called split for bar buttons * Added wavy button styles. * Added padding configuration * Update bar padding * Fix styling for battery style2 * Fix icon only setting for bar * Update types and options * Add button style to exported theme props. * Fix top margin for menus. --- lib/types/bar.d.ts | 9 +++ lib/types/options.d.ts | 1 + modules/bar/Bar.ts | 8 ++- modules/bar/battery/index.ts | 17 ++++- modules/bar/bluetooth/index.ts | 11 ++- modules/bar/media/index.ts | 21 ++++-- modules/bar/menu/index.ts | 10 ++- modules/bar/network/index.ts | 14 +++- modules/bar/notifications/index.ts | 8 +++ modules/bar/systray/index.ts | 1 + modules/bar/volume/index.ts | 17 +++-- modules/bar/window_title/index.ts | 22 ++++-- modules/menus/bluetooth/devices/devicelist.ts | 3 +- modules/shared/barItemBox.ts | 20 +++++- options.ts | 20 +++++- scss/style/bar/audio.scss | 19 ++++++ scss/style/bar/bar.scss | 67 ++++++++++++++++++- scss/style/bar/battery.scss | 40 ++++++----- scss/style/bar/bluetooth.scss | 18 +++++ scss/style/bar/clock.scss | 4 ++ scss/style/bar/media.scss | 18 +++++ scss/style/bar/menu.scss | 4 ++ scss/style/bar/network.scss | 18 +++++ scss/style/bar/notifications.scss | 20 +++++- scss/style/bar/systray.scss | 6 +- scss/style/bar/window_title.scss | 18 +++++ scss/style/bar/workspace.scss | 4 ++ scss/style/menus/menu.scss | 2 +- widget/settings/pages/config/bar/index.ts | 29 +++++++- widget/settings/pages/theme/bar/index.ts | 49 ++++++++++++++ widget/settings/shared/FileChooser.ts | 19 ++++++ 31 files changed, 459 insertions(+), 58 deletions(-) create mode 100644 lib/types/bar.d.ts diff --git a/lib/types/bar.d.ts b/lib/types/bar.d.ts new file mode 100644 index 0000000..565bf55 --- /dev/null +++ b/lib/types/bar.d.ts @@ -0,0 +1,9 @@ +import { Variable } from "types/variable"; + +export type Child = { + component: Box; + isVisible?: boolean; + isVis?: Variable; + boxClass: string; + props: ButtonProps; +}; diff --git a/lib/types/options.d.ts b/lib/types/options.d.ts index d9b4874..9c6330e 100644 --- a/lib/types/options.d.ts +++ b/lib/types/options.d.ts @@ -5,6 +5,7 @@ export type Unit = "imperial" | "metric"; export type PowerOptions = "sleep" | "reboot" | "logout" | "shutdown"; export type NotificationAnchor = "top" | "top right" | "top left" | "bottom" | "bottom right" | "bottom left" | "left" | "right"; export type OSDAnchor = "top left" | "top" | "top right" | "right" | "bottom right" | "bottom" | "bottom left" | "left"; +export type BarButtonStyles = "default" | "split" | "wave" | "wave2"; export type ThemeExportData = { filePath: string, diff --git a/modules/bar/Bar.ts b/modules/bar/Bar.ts index f09d029..371e623 100644 --- a/modules/bar/Bar.ts +++ b/modules/bar/Bar.ts @@ -14,6 +14,8 @@ const hyprland = await Service.import("hyprland"); import { BarItemBox as WidgetContainer } from "../shared/barItemBox.js"; import options from "options"; import Gdk from "gi://Gdk?version=3.0"; +import Button from "types/widgets/button.js"; +import Gtk from "types/@girs/gtk-3.0/gtk-3.0.js"; const { layouts } = options.bar; @@ -241,7 +243,7 @@ export const Bar = (() => { setup: self => { self.hook(layouts, (self) => { const foundLayout = getModulesForMonitor(hyprlandMonitor, layouts.value as BarLayout); - self.children = foundLayout.left.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor)); + self.children = foundLayout.left.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button); }); }, }), @@ -251,7 +253,7 @@ export const Bar = (() => { setup: self => { self.hook(layouts, (self) => { const foundLayout = getModulesForMonitor(hyprlandMonitor, layouts.value as BarLayout); - self.children = foundLayout.middle.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor)); + self.children = foundLayout.middle.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button); }); }, }), @@ -261,7 +263,7 @@ export const Bar = (() => { setup: self => { self.hook(layouts, (self) => { const foundLayout = getModulesForMonitor(hyprlandMonitor, layouts.value as BarLayout); - self.children = foundLayout.right.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor)); + self.children = foundLayout.right.filter(mod => Object.keys(widget).includes(mod)).map(w => widget[w](hyprlandMonitor) as Button); }); }, }), diff --git a/modules/bar/battery/index.ts b/modules/bar/battery/index.ts index fe9361d..e35c511 100644 --- a/modules/bar/battery/index.ts +++ b/modules/bar/battery/index.ts @@ -1,6 +1,5 @@ const battery = await Service.import("battery"); import Gdk from 'gi://Gdk?version=3.0'; -import EventHandler from 'types/widgets/button.ts' import { openMenu } from "../utils.js"; import options from "options"; @@ -42,7 +41,14 @@ const BatteryLabel = () => { return { component: Widget.Box({ - class_name: "battery", + className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_label.bind("value")], (style, showLabel) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + }; + return `battery ${styleMap[style]} ${!showLabel ? "no-label" : ""}`; + }), visible: battery.bind("available"), tooltip_text: battery.bind("time_remaining").as((t) => t.toString()), children: Utils.merge( @@ -60,7 +66,12 @@ const BatteryLabel = () => { }), ]; } else if (batAvail && !showLabel) { - return [Widget.Icon({ icon: batIcon })]; + return [ + Widget.Icon({ + class_name: "bar-button-icon battery", + icon: batIcon + }) + ]; } else { return []; } diff --git a/modules/bar/bluetooth/index.ts b/modules/bar/bluetooth/index.ts index cf36e5a..8d1662b 100644 --- a/modules/bar/bluetooth/index.ts +++ b/modules/bar/bluetooth/index.ts @@ -3,6 +3,8 @@ import Gdk from 'gi://Gdk?version=3.0'; import options from "options"; import { openMenu } from "../utils.js"; +const { label } = options.bar.bluetooth; + const Bluetooth = () => { const btIcon = Widget.Label({ label: bluetooth.bind("enabled").as((v) => v ? "󰂯" : "󰂲"), @@ -25,7 +27,14 @@ const Bluetooth = () => { return { component: Widget.Box({ - class_name: "volume", + className: Utils.merge([options.theme.bar.buttons.style.bind("value"), label.bind("value")], (style, showLabel) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + }; + return `bluetooth ${styleMap[style]} ${!showLabel ? "no-label" : ""}`; + }), children: options.bar.bluetooth.label.bind("value").as((showLabel) => { if (showLabel) { return [btIcon, btText]; diff --git a/modules/bar/media/index.ts b/modules/bar/media/index.ts index 7464dd0..b3892d3 100644 --- a/modules/bar/media/index.ts +++ b/modules/bar/media/index.ts @@ -16,12 +16,12 @@ const Media = () => { const getIconForPlayer = (playerName: string): string => { const windowTitleMap = [ - ["Firefox", "󰈹 "], - ["Microsoft Edge", "󰇩 "], - ["Discord", " "], - ["Plex", "󰚺 "], - ["Spotify", "󰓇 "], - ["(.*)", "󰝚 "], + ["Firefox", "󰈹"], + ["Microsoft Edge", "󰇩"], + ["Discord", ""], + ["Plex", "󰚺"], + ["Spotify", "󰓇"], + ["(.*)", "󰝚"], ]; const foundMatch = windowTitleMap.find((wt) => @@ -59,7 +59,14 @@ const Media = () => { component: Widget.Box({ visible: false, child: Widget.Box({ - class_name: "media", + className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_label.bind("value")], (style, showLabel) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + }; + return `media ${styleMap[style]}`; + }), child: Widget.Box({ children: [ Widget.Label({ diff --git a/modules/bar/menu/index.ts b/modules/bar/menu/index.ts index c4f1ca5..a258dc5 100644 --- a/modules/bar/menu/index.ts +++ b/modules/bar/menu/index.ts @@ -5,8 +5,16 @@ import options from "options"; const Menu = () => { return { component: Widget.Box({ + className: Utils.merge([options.theme.bar.buttons.style.bind("value")], (style) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + }; + return `dashboard ${styleMap[style]}`; + }), child: Widget.Label({ - class_name: "bar-menu_label txt-icon bar", + class_name: "bar-menu_label bar-button_icon txt-icon bar", label: options.bar.launcher.icon.bind("value"), }), }), diff --git a/modules/bar/network/index.ts b/modules/bar/network/index.ts index 8edc404..da944fa 100644 --- a/modules/bar/network/index.ts +++ b/modules/bar/network/index.ts @@ -8,8 +8,16 @@ const { label: networkLabel, truncation, truncation_size } = options.bar.network const Network = () => { return { component: Widget.Box({ - vpack: "center", - class_name: "bar-network", + vpack: "fill", + vexpand: true, + className: Utils.merge([options.theme.bar.buttons.style.bind("value"), networkLabel.bind("value")], (style, showLabel) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + }; + return `network ${styleMap[style]}${!showLabel ? " no-label" : ""}`; + }), children: [ Widget.Icon({ class_name: "bar-button-icon network", @@ -25,7 +33,7 @@ const Network = () => { }) }), Widget.Box({ - class_name: "bar-button-icon network", + vpack: "center", child: Utils.merge([ network.bind("primary"), network.bind("wifi"), diff --git a/modules/bar/notifications/index.ts b/modules/bar/notifications/index.ts index d09507f..f168a4e 100644 --- a/modules/bar/notifications/index.ts +++ b/modules/bar/notifications/index.ts @@ -10,6 +10,14 @@ export const Notifications = () => { return { component: Widget.Box({ hpack: "start", + className: Utils.merge([options.theme.bar.buttons.style.bind("value"), show_total.bind("value")], (style, showTotal) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + }; + return `notifications ${styleMap[style]} ${!showTotal ? "no-label" : ""}`; + }), child: Widget.Box({ hpack: "start", class_name: "bar-notifications", diff --git a/modules/bar/systray/index.ts b/modules/bar/systray/index.ts index 7b44612..1d4cc0e 100644 --- a/modules/bar/systray/index.ts +++ b/modules/bar/systray/index.ts @@ -41,6 +41,7 @@ const SysTray = () => { isVisible: true, boxClass: "systray", isVis, + props: {} }; }; diff --git a/modules/bar/volume/index.ts b/modules/bar/volume/index.ts index 6f5a64a..4c62062 100644 --- a/modules/bar/volume/index.ts +++ b/modules/bar/volume/index.ts @@ -26,21 +26,30 @@ const Volume = () => { }; const volIcn = Widget.Label({ - vpack: "center", + hexpand: true, label: getIcon(), class_name: "bar-button-icon volume txt-icon bar", }); const volPct = Widget.Label({ - vpack: "center", + hexpand: true, label: audio.speaker.bind("volume").as((v) => `${Math.round(v * 100)}%`), class_name: "bar-button-label volume", }); return { component: Widget.Box({ - vpack: "center", - class_name: "volume", + hexpand: true, + vexpand: true, + className: Utils.merge([options.theme.bar.buttons.style.bind("value"), options.bar.volume.label.bind("value")], (style, showLabel) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + }; + + return `volume ${styleMap[style]} ${!showLabel ? "no-label" : ""}`; + }), children: options.bar.volume.label.bind("value").as((showLabel) => { if (showLabel) { return [volIcn, volPct]; diff --git a/modules/bar/window_title/index.ts b/modules/bar/window_title/index.ts index c6317ea..58a887c 100644 --- a/modules/bar/window_title/index.ts +++ b/modules/bar/window_title/index.ts @@ -135,19 +135,29 @@ const filterTitle = (windowtitle: ActiveClient) => { const ClientTitle = () => { return { component: Widget.Box({ - children: [ - Widget.Label({ + className: Utils.merge([options.theme.bar.buttons.style.bind("value"), options.bar.windowtitle.label.bind("value")], (style, showLabel) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + }; + return `windowtitle ${styleMap[style]} ${!showLabel ? "no-label" : ""}`; + }), + children: options.bar.windowtitle.label.bind("value").as((showLabel) => { + const titleIcon = Widget.Label({ class_name: "bar-button-icon windowtitle txt-icon bar", label: hyprland.active.bind("client").as((v) => filterTitle(v).icon), - }), - Widget.Label({ + }); + const titleLabel = Widget.Label({ class_name: "bar-button-label windowtitle", label: hyprland.active.bind("client").as((v) => filterTitle(v).label), - }) - ] + }); + return showLabel ? [titleIcon, titleLabel] : [titleIcon]; + }), }), isVisible: true, boxClass: "windowtitle", + props: {} }; }; diff --git a/modules/menus/bluetooth/devices/devicelist.ts b/modules/menus/bluetooth/devices/devicelist.ts index c5e948a..6827145 100644 --- a/modules/menus/bluetooth/devices/devicelist.ts +++ b/modules/menus/bluetooth/devices/devicelist.ts @@ -2,8 +2,9 @@ import { Bluetooth } from "types/service/bluetooth.js"; import Box from "types/widgets/box.js"; import { connectedControls } from "./connectedControls.js"; import { getBluetoothIcon } from "../utils.js"; +import Gtk from "types/@girs/gtk-3.0/gtk-3.0.js"; -const devices = (bluetooth: Bluetooth, self: Box) => { +const devices = (bluetooth: Bluetooth, self: Box) => { return self.hook(bluetooth, () => { if (!bluetooth.enabled) { return (self.child = Widget.Box({ diff --git a/modules/shared/barItemBox.ts b/modules/shared/barItemBox.ts index fb25c6b..676a455 100644 --- a/modules/shared/barItemBox.ts +++ b/modules/shared/barItemBox.ts @@ -1,13 +1,27 @@ -export const BarItemBox = (child) => { +import Gtk from "gi://Gtk?version=3.0"; +import { Child } from "lib/types/bar"; +import options from "options"; +import { ButtonProps } from "types/widgets/button"; + +export const BarItemBox = (child: Child): ButtonProps => { const computeVisible = () => { - if (Object.hasOwnProperty.call(child, "isVis")) { + if (child.isVis !== undefined) { return child.isVis.bind("value"); } return child.isVisible; }; return Widget.Button({ - class_name: `bar_item_box_visible ${Object.hasOwnProperty.call(child, "boxClass") ? child.boxClass : ""}`, + class_name: options.theme.bar.buttons.style.bind("value").as((style) => { + const styleMap = { + default: "style1", + split: "style2", + wave: "style3", + wave2: "style4", + }; + + return `bar_item_box_visible ${styleMap[style]} ${Object.hasOwnProperty.call(child, "boxClass") ? child.boxClass : ""}`; + }), child: child.component, visible: computeVisible(), ...child.props, diff --git a/options.ts b/options.ts index e9b3296..925bc3c 100644 --- a/options.ts +++ b/options.ts @@ -1,5 +1,5 @@ import { opt, mkOptions } from "lib/option" -import { NotificationAnchor, OSDAnchor, OSDOrientation } from "lib/types/options"; +import { BarButtonStyles, NotificationAnchor, OSDAnchor, OSDOrientation } from "lib/types/options"; import { MatugenScheme, MatugenTheme, MatugenVariation } from "lib/types/options"; // WARN: CHANGING THESE VALUES WILL PREVENT MATUGEN COLOR GENERATION FOR THE CHANGED VALUE @@ -135,21 +135,26 @@ const options = mkOptions(OPTIONS, { transparent: opt(false), background: opt(colors.crust), buttons: { + style: opt("default"), monochrome: opt(false), spacing: opt("0.25em"), + padding_x: opt("0.7rem"), + padding_y: opt("0.2rem"), y_margins: opt("0.4em"), radius: opt("0.3em"), opacity: opt(100), background_opacity: opt(100), background_hover_opacity: opt(100), background: opt(colors.base2), + icon_background: opt(colors.base2), hover: opt(colors.surface1), text: opt(colors.lavender), icon: opt(colors.lavender), dashboard: { background: opt(colors.base2), hover: opt(colors.surface1), - icon: opt(colors.yellow) + icon: opt(colors.yellow), + spacing: opt("0.5em"), }, workspaces: { background: opt(colors.base2), @@ -161,12 +166,14 @@ const options = mkOptions(OPTIONS, { numbered_active_highlight_padding: opt("0.2em"), numbered_active_highlighted_text_color: opt(colors.mantle), numbered_active_underline_color: opt(colors.pink), + spacing: opt("0.5em"), }, windowtitle: { background: opt(colors.base2), hover: opt(colors.surface1), text: opt(colors.pink), icon: opt(colors.pink), + icon_background: opt(colors.base2), spacing: opt("0.5em"), }, media: { @@ -174,6 +181,7 @@ const options = mkOptions(OPTIONS, { hover: opt(colors.surface1), text: opt(colors.lavender), icon: opt(colors.lavender), + icon_background: opt(colors.base2), spacing: opt("0.5em"), }, volume: { @@ -181,6 +189,7 @@ const options = mkOptions(OPTIONS, { hover: opt(colors.surface1), text: opt(colors.maroon), icon: opt(colors.maroon), + icon_background: opt(colors.base2), spacing: opt("0.5em"), }, network: { @@ -188,6 +197,7 @@ const options = mkOptions(OPTIONS, { hover: opt(colors.surface1), text: opt(colors.mauve), icon: opt(colors.mauve), + icon_background: opt(colors.base2), spacing: opt("0.5em"), }, bluetooth: { @@ -195,17 +205,20 @@ const options = mkOptions(OPTIONS, { hover: opt(colors.surface1), text: opt(colors.sky), icon: opt(colors.sky), + icon_background: opt(colors.base2), spacing: opt("0.5em"), }, systray: { background: opt(colors.base2), hover: opt(colors.surface1), + spacing: opt("0.5em"), }, battery: { background: opt(colors.base2), hover: opt(colors.surface1), text: opt(colors.yellow), icon: opt(colors.yellow), + icon_background: opt(colors.base2), spacing: opt("0.5em"), }, clock: { @@ -213,11 +226,13 @@ const options = mkOptions(OPTIONS, { hover: opt(colors.surface1), text: opt(colors.pink), icon: opt(colors.pink), + spacing: opt("0.5em"), }, notifications: { background: opt(colors.base2), hover: opt(colors.surface1), icon: opt(colors.lavender), + icon_background: opt(colors.base2), total: opt(colors.lavender), spacing: opt("0.5em"), }, @@ -687,6 +702,7 @@ const options = mkOptions(OPTIONS, { }, windowtitle: { title_map: opt([]), + label: opt(true), }, workspaces: { show_icons: opt(false), diff --git a/scss/style/bar/audio.scss b/scss/style/bar/audio.scss index f585bf6..1bb7d7f 100644 --- a/scss/style/bar/audio.scss +++ b/scss/style/bar/audio.scss @@ -5,5 +5,24 @@ .bar-button-label.volume { color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-volume-text); + min-width: 2.2em; margin-left: $bar-buttons-volume-spacing; } + +.style2 { + .bar-button-icon.volume { + border-top-left-radius: $bar-buttons-radius; + border-bottom-left-radius: $bar-buttons-radius; + background: if($bar-buttons-monochrome, $bar-buttons-icon_background, $bar-buttons-volume-icon_background); + padding: $bar-buttons-padding_y 0em; + padding-left: $bar-buttons-padding_x; + padding-right: $bar-buttons-volume-spacing; + } + + .bar-button-label.volume { + padding: $bar-buttons-padding_y 0em; + padding-right: $bar-buttons-padding_x; + padding-left: $bar-buttons-volume-spacing; + margin-left: 0em; + } +} diff --git a/scss/style/bar/bar.scss b/scss/style/bar/bar.scss index 5397f89..37bdcaa 100644 --- a/scss/style/bar/bar.scss +++ b/scss/style/bar/bar.scss @@ -28,9 +28,19 @@ $transparency-value-hover: 1 - $bar-button-background-hover-opacity-ratio; .bar_item_box_visible { background-color: transparentize($bar-buttons-background, $transparency-value); border-radius: $bar-buttons-radius; - padding: 0.2rem 0.9rem; margin: $bar-buttons-y_margins $bar-buttons-spacing; opacity: $bar-buttons-opacity/100; + padding: $bar-buttons-padding_y $bar-buttons-padding_x; + + &.style3 { + border-bottom-left-radius: 1.3em; + border-top-right-radius: 1.3em; + } + + &.style4 { + border-bottom-right-radius: 1.3em; + border-top-left-radius: 1.3em; + } &:hover { background: transparentize($bar-buttons-hover, $transparency-value-hover); @@ -119,6 +129,61 @@ $transparency-value-hover: 1 - $bar-button-background-hover-opacity-ratio; &.workspaces { background-color: transparentize(if($bar-buttons-monochrome, $bar-buttons-background, $bar-buttons-workspaces-background), $transparency-value); } + + &.style2 { + padding: 0em; + + + &:hover { + .dashboard .bar-button_icon { + color: $bar-buttons-dashboard_background; + } + } + + &:hover .no-label { + .battery .bar-button-icon { + background-color: transparentize(if($bar-buttons-monochrome, $bar-buttons-hover, $bar-buttons-battery-hover), $transparency-value); + color: $bar-buttons-battery-icon_background; + } + + .bluetooth.bar-button-icon { + background-color: transparentize(if($bar-buttons-monochrome, $bar-buttons-hover, $bar-buttons-bluetooth-hover), $transparency-value); + color: $bar-buttons-bluetooth-icon_background; + } + + .media.bar-button-icon { + background-color: transparentize(if($bar-buttons-monochrome, $bar-buttons-hover, $bar-buttons-media-hover), $transparency-value); + color: $bar-buttons-media-icon_background; + } + + .network.bar-button-icon { + background-color: transparentize(if($bar-buttons-monochrome, $bar-buttons-hover, $bar-buttons-network-hover), $transparency-value); + color: $bar-buttons-network-icon_background; + } + + .notifications.bar-button-icon { + background-color: transparentize(if($bar-buttons-monochrome, $bar-buttons-hover, $bar-buttons-notifications-hover), $transparency-value); + color: $bar-buttons-notifications-icon_background; + } + + .volume.bar-button-icon { + background-color: transparentize(if($bar-buttons-monochrome, $bar-buttons-hover, $bar-buttons-volume-hover), $transparency-value); + color: $bar-buttons-volume-icon_background; + } + + .windowtitle.bar-button-icon { + background-color: transparentize(if($bar-buttons-monochrome, $bar-buttons-hover, $bar-buttons-windowtitle-hover), $transparency-value); + color: $bar-buttons-windowtitle-icon_background; + } + } + } +} + +.no-label.style2 { + .bar-button-icon { + border-top-right-radius: $bar-buttons-radius; + border-bottom-right-radius: $bar-buttons-radius; + } } .bar_item_box_hidden { diff --git a/scss/style/bar/battery.scss b/scss/style/bar/battery.scss index 9b2acfb..51955d4 100644 --- a/scss/style/bar/battery.scss +++ b/scss/style/bar/battery.scss @@ -1,20 +1,26 @@ -.bar { - .battery { - .bar-button-label.battery { - color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-battery-text); - margin-left: $bar-buttons-battery-spacing; - } +.bar-button-label.battery { + color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-battery-text); + margin-left: $bar-buttons-battery-spacing; +} - .bar-button-icon.battery { - color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-battery-icon); - } +.bar-button-icon.battery { + color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-battery-icon); +} + +.style2 { + .bar-button-icon.battery { + border-top-left-radius: $bar-buttons-radius; + border-bottom-left-radius: $bar-buttons-radius; + background: if($bar-buttons-monochrome, $bar-buttons-icon_background, $bar-buttons-battery-icon_background); + padding: $bar-buttons-padding_y 0em; + padding-left: $bar-buttons-padding_x; + padding-right: $bar-buttons-battery-spacing; + } + + .bar-button-label.battery { + padding: $bar-buttons-padding_y 0em; + padding-right: $bar-buttons-padding_x; + padding-left: $bar-buttons-battery-spacing; + margin-left: 0em; } } - -.menu-section-container.brightness { - margin-bottom: 0em; -} - -.menu-section-container.energy { - margin-top: 0.5em; -} diff --git a/scss/style/bar/bluetooth.scss b/scss/style/bar/bluetooth.scss index 3c83ac3..c79a9c5 100644 --- a/scss/style/bar/bluetooth.scss +++ b/scss/style/bar/bluetooth.scss @@ -18,3 +18,21 @@ .menu-button-isactive { color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-bluetooth-text); } + +.style2 { + .bar-button-icon.bluetooth { + border-top-left-radius: $bar-buttons-radius; + border-bottom-left-radius: $bar-buttons-radius; + background: if($bar-buttons-monochrome, $bar-buttons-icon_background, $bar-buttons-bluetooth-icon_background); + padding: $bar-buttons-padding_y 0em; + padding-left: $bar-buttons-padding_x; + padding-right: $bar-buttons-bluetooth-spacing; + } + + .bar-button-label.bluetooth { + padding: $bar-buttons-padding_y 0em; + padding-right: $bar-buttons-padding_x; + padding-left: $bar-buttons-bluetooth-spacing; + margin-left: 0em; + } +} diff --git a/scss/style/bar/clock.scss b/scss/style/bar/clock.scss index 331bc22..26533de 100644 --- a/scss/style/bar/clock.scss +++ b/scss/style/bar/clock.scss @@ -1,3 +1,7 @@ .clock { color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-clock-text); } + +.style2.clock { + padding: $bar-buttons-padding_y $bar-buttons-padding_x; +} diff --git a/scss/style/bar/media.scss b/scss/style/bar/media.scss index 177b797..7ed7246 100644 --- a/scss/style/bar/media.scss +++ b/scss/style/bar/media.scss @@ -7,3 +7,21 @@ font-size: 1.2em; color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-media-icon); } + +.style2 { + .bar-button-icon.media { + border-top-left-radius: $bar-buttons-radius; + border-bottom-left-radius: $bar-buttons-radius; + background: if($bar-buttons-monochrome, $bar-buttons-icon_background, $bar-buttons-media-icon_background); + padding: $bar-buttons-padding_y 0em; + padding-left: $bar-buttons-padding_x; + padding-right: $bar-buttons-media-spacing; + } + + .bar-button-label.media { + padding: $bar-buttons-padding_y 0em; + padding-right: $bar-buttons-padding_x; + padding-left: $bar-buttons-media-spacing; + margin-left: 0em; + } +} diff --git a/scss/style/bar/menu.scss b/scss/style/bar/menu.scss index 84d7908..2ab4059 100644 --- a/scss/style/bar/menu.scss +++ b/scss/style/bar/menu.scss @@ -2,3 +2,7 @@ color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-dashboard-icon); font-size: 1.3em; } + +.style2 .bar-menu_label { + padding: $bar-buttons-padding_y $bar-buttons-padding_x; +} diff --git a/scss/style/bar/network.scss b/scss/style/bar/network.scss index e7531a0..6d0c411 100644 --- a/scss/style/bar/network.scss +++ b/scss/style/bar/network.scss @@ -6,3 +6,21 @@ .bar-button-icon.network { color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-network-icon); } + +.style2 { + .bar-button-icon.network { + border-top-left-radius: $bar-buttons-radius; + border-bottom-left-radius: $bar-buttons-radius; + background: if($bar-buttons-monochrome, $bar-buttons-icon_background, $bar-buttons-network-icon_background); + padding: $bar-buttons-padding_y 0em; + padding-left: $bar-buttons-padding_x; + padding-right: $bar-buttons-network-spacing; + } + + .bar-button-label.network { + padding: $bar-buttons-padding_y 0em; + padding-right: $bar-buttons-padding_x; + padding-left: $bar-buttons-network-spacing; + margin-left: 0em; + } +} diff --git a/scss/style/bar/notifications.scss b/scss/style/bar/notifications.scss index 94f5ba7..529dd0f 100644 --- a/scss/style/bar/notifications.scss +++ b/scss/style/bar/notifications.scss @@ -1,10 +1,28 @@ .bar-button-icon.notifications { color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-notifications-icon); font-size: 1.3em; - min-width: 1em; } .bar-button-label.notifications { color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-notifications-total); margin-left: $bar-buttons-notifications-spacing; + min-width: 1em; +} + +.style2 { + .bar-button-icon.notifications { + border-top-left-radius: $bar-buttons-radius; + border-bottom-left-radius: $bar-buttons-radius; + background: if($bar-buttons-monochrome, $bar-buttons-icon_background, $bar-buttons-notifications-icon_background); + padding: $bar-buttons-padding_y 0em; + padding-left: $bar-buttons-padding_x; + padding-right: $bar-buttons-notifications-spacing; + } + + .bar-button-label.notifications { + padding: $bar-buttons-padding_y 0em; + padding-right: $bar-buttons-padding_x; + padding-left: $bar-buttons-notifications-spacing; + margin-left: 0em; + } } diff --git a/scss/style/bar/systray.scss b/scss/style/bar/systray.scss index e69aed6..dcd3716 100644 --- a/scss/style/bar/systray.scss +++ b/scss/style/bar/systray.scss @@ -1,7 +1,11 @@ .systray button:not(:first-child) { - margin-left: 0.75rem; + margin-left: $bar-buttons-systray-spacing; } .systray-icon { font-size: 1.3em; } + +.style2.systray { + padding: $bar-buttons-padding_y $bar-buttons-padding_x; +} diff --git a/scss/style/bar/window_title.scss b/scss/style/bar/window_title.scss index 7eb99a3..a258355 100644 --- a/scss/style/bar/window_title.scss +++ b/scss/style/bar/window_title.scss @@ -6,3 +6,21 @@ color: if($bar-buttons-monochrome, $bar-buttons-text, $bar-buttons-windowtitle-text); margin-left: $bar-buttons-windowtitle-spacing; } + +.style2 { + .bar-button-icon.windowtitle { + border-top-left-radius: $bar-buttons-radius; + border-bottom-left-radius: $bar-buttons-radius; + background: if($bar-buttons-monochrome, $bar-buttons-icon_background, $bar-buttons-windowtitle-icon_background); + padding: $bar-buttons-padding_y 0em; + padding-left: $bar-buttons-padding_x; + padding-right: $bar-buttons-windowtitle-spacing; + } + + .bar-button-label.windowtitle { + padding: $bar-buttons-padding_y 0em; + padding-right: $bar-buttons-padding_x; + padding-left: $bar-buttons-windowtitle-spacing; + margin-left: 0em; + } +} diff --git a/scss/style/bar/workspace.scss b/scss/style/bar/workspace.scss index 451e744..776c7f5 100644 --- a/scss/style/bar/workspace.scss +++ b/scss/style/bar/workspace.scss @@ -75,3 +75,7 @@ border-radius: $bar-buttons-workspaces-numbered_active_highlight_border; } } + +.style2.workspaces { + padding: $bar-buttons-padding_y $bar-buttons-padding_x; +} diff --git a/scss/style/menus/menu.scss b/scss/style/menus/menu.scss index d6938d4..55c9f80 100644 --- a/scss/style/menus/menu.scss +++ b/scss/style/menus/menu.scss @@ -235,7 +235,7 @@ .event-top-padding * { min-height: 0em; - margin-top: 2.8em + if($bar-floating, $bar-margin_top, 0em); + margin-top: 2.8em + if($bar-floating, $bar-margin_top * 1.1, $bar-margin_top * 0.1); } @keyframes spin { diff --git a/widget/settings/pages/config/bar/index.ts b/widget/settings/pages/config/bar/index.ts index ab49c3c..8a6b0fa 100644 --- a/widget/settings/pages/config/bar/index.ts +++ b/widget/settings/pages/config/bar/index.ts @@ -12,12 +12,21 @@ export const BarSettings = () => { vertical: true, children: [ Header('Layouts'), - Option({ opt: options.bar.layouts, title: 'Bar Layouts for Monitors', subtitle: 'Wiki Link: https://hyprpanel.com/configuration/panel.html#layouts', type: 'object', subtitleLink: 'https://hyprpanel.com/configuration/panel.html#layouts' }, 'bar-layout-input'), + Option({ + opt: options.bar.layouts, + title: 'Bar Layouts for Monitors', + subtitle: 'Wiki Link: https://hyprpanel.com/configuration/panel.html#layouts', + type: 'object', + subtitleLink: 'https://hyprpanel.com/configuration/panel.html#layouts' + }, + 'bar-layout-input'), Header('Spacing'), Option({ opt: options.theme.bar.outer_spacing, title: 'Outer Spacing', subtitle: 'Spacing on the outer left and right edges of the bar.', type: 'string' }), Option({ opt: options.theme.bar.buttons.y_margins, title: 'Vertical Margins', subtitle: 'Spacing above/below the buttons in the bar.', type: 'string' }), Option({ opt: options.theme.bar.buttons.spacing, title: 'Button Spacing', subtitle: 'Spacing between the buttons in the bar.', type: 'string' }), + Option({ opt: options.theme.bar.buttons.padding_x, title: 'Button Horizontal Padding', type: 'string' }), + Option({ opt: options.theme.bar.buttons.padding_y, title: 'Button Vertical Padding', type: 'string' }), Option({ opt: options.theme.bar.buttons.radius, title: 'Button Radius', type: 'string' }), Option({ opt: options.theme.bar.floating, title: 'Floating Bar', type: 'boolean' }), Option({ opt: options.theme.bar.layer, title: 'Layer', type: 'enum', subtitle: 'Layer determines the Z index of your bar.', enums: ["top", "bottom", "overlay", "background"] }), @@ -41,13 +50,27 @@ export const BarSettings = () => { Option({ opt: options.bar.workspaces.spacing, title: 'Spacing', subtitle: 'Spacing between workspace icons', type: 'float' }), Option({ opt: options.bar.workspaces.workspaces, title: 'Total Workspaces', type: 'number' }), Option({ opt: options.bar.workspaces.monitorSpecific, title: 'Monitor Specific', subtitle: 'Only workspaces applicable to the monitor will be displayed', type: 'boolean' }), - Option({ opt: options.bar.workspaces.workspaceMask, title: 'Mask Workspace Numbers On Monitors', subtitle: 'Only applicable if Workspace Numbers and Monitor Specific are enabled.\nForces each Monitor\'s Workspace labels to start from 1.', type: 'boolean' }), + Option({ + opt: options.bar.workspaces.workspaceMask, + title: 'Mask Workspace Numbers On Monitors', + + subtitle: `Only applicable if Workspace Numbers and Monitor Specific are enabled. +Forces each Monitor's Workspace labels to start from 1.`, + type: 'boolean' + }), Option({ opt: options.bar.workspaces.reverse_scroll, title: 'Invert Scroll', subtitle: 'Scrolling up will go to the previous workspace rather than the next.', type: 'boolean' }), Option({ opt: options.bar.workspaces.scroll_speed, title: 'Scrolling Speed', type: 'number' }), Header('Window Titles'), + Option({ opt: options.bar.windowtitle.label, title: 'Show Window Title Label', type: 'boolean' }), Option({ opt: options.theme.bar.buttons.windowtitle.spacing, title: 'Inner Spacing', subtitle: 'Spacing between the icon and the label inside the buttons.', type: 'string' }), - Option({ opt: options.bar.windowtitle.title_map, title: 'Window Title Mappings', subtitle: 'Wiki Link: https://hyprpanel.com/configuration/panel.html#window-title-mappings', type: 'object', subtitleLink: 'https://hyprpanel.com/configuration/panel.html#window-title-mappings' }), + Option({ + opt: options.bar.windowtitle.title_map, + title: 'Window Title Mappings', + subtitle: 'Wiki Link: https://hyprpanel.com/configuration/panel.html#window-title-mappings', + type: 'object', + subtitleLink: 'https://hyprpanel.com/configuration/panel.html#window-title-mappings' + }), Header('Volume'), Option({ opt: options.bar.volume.label, title: 'Show Volume Percentage', type: 'boolean' }), diff --git a/widget/settings/pages/theme/bar/index.ts b/widget/settings/pages/theme/bar/index.ts index d80efd3..4467f8f 100644 --- a/widget/settings/pages/theme/bar/index.ts +++ b/widget/settings/pages/theme/bar/index.ts @@ -14,6 +14,7 @@ export const BarTheme = () => { Header('General'), Option({ opt: options.theme.bar.transparent, title: 'Transparent', type: 'boolean' }), Option({ opt: options.theme.bar.background, title: 'Background Color', type: 'color' }), + Option({ opt: options.theme.bar.buttons.style, title: 'Button Style', type: 'enum', enums: ['default', 'split', 'wave', 'wave2'] }), Option({ opt: options.theme.bar.opacity, title: 'Background Opacity', type: 'number', increment: 5, min: 0, max: 100 }), Option({ opt: options.theme.bar.buttons.opacity, title: 'Button Opacity', type: 'number', increment: 5, min: 0, max: 100 }), Option({ opt: options.theme.bar.buttons.background_opacity, title: 'Button Background Opacity', type: 'number', increment: 5, min: 0, max: 100 }), @@ -23,6 +24,12 @@ export const BarTheme = () => { Option({ opt: options.theme.bar.buttons.hover, title: 'Button Hover', type: 'color' }), Option({ opt: options.theme.bar.buttons.text, title: 'Button Text', type: 'color' }), Option({ opt: options.theme.bar.buttons.icon, title: 'Button Icon', type: 'color' }), + Option({ + opt: options.theme.bar.buttons.icon_background, + title: 'Button Icon Background', + subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.', + type: 'color' + }), Header('Dashboard Button'), Option({ opt: options.theme.bar.buttons.dashboard.background, title: 'Background', type: 'color' }), @@ -43,30 +50,60 @@ export const BarTheme = () => { Option({ opt: options.theme.bar.buttons.windowtitle.hover, title: 'Hover', type: 'color' }), Option({ opt: options.theme.bar.buttons.windowtitle.text, title: 'Text', type: 'color' }), Option({ opt: options.theme.bar.buttons.windowtitle.icon, title: 'Icon', type: 'color' }), + Option({ + opt: options.theme.bar.buttons.windowtitle.icon_background, + title: 'Button Icon Background', + subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.', + type: 'color' + }), Header('Media'), Option({ opt: options.theme.bar.buttons.media.background, title: 'Background', type: 'color' }), Option({ opt: options.theme.bar.buttons.media.hover, title: 'Hover', type: 'color' }), Option({ opt: options.theme.bar.buttons.media.text, title: 'Text', type: 'color' }), Option({ opt: options.theme.bar.buttons.media.icon, title: 'Icon', type: 'color' }), + Option({ + opt: options.theme.bar.buttons.media.icon_background, + title: 'Button Icon Background', + subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.', + type: 'color' + }), Header('Volume'), Option({ opt: options.theme.bar.buttons.volume.background, title: 'Background', type: 'color' }), Option({ opt: options.theme.bar.buttons.volume.hover, title: 'Hover', type: 'color' }), Option({ opt: options.theme.bar.buttons.volume.text, title: 'Text', type: 'color' }), Option({ opt: options.theme.bar.buttons.volume.icon, title: 'Icon', type: 'color' }), + Option({ + opt: options.theme.bar.buttons.volume.icon_background, + title: 'Button Icon Background', + subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.', + type: 'color' + }), Header('Network'), Option({ opt: options.theme.bar.buttons.network.background, title: 'Background', type: 'color' }), Option({ opt: options.theme.bar.buttons.network.hover, title: 'Hover', type: 'color' }), Option({ opt: options.theme.bar.buttons.network.text, title: 'Text', type: 'color' }), Option({ opt: options.theme.bar.buttons.network.icon, title: 'Icon', type: 'color' }), + Option({ + opt: options.theme.bar.buttons.network.icon_background, + title: 'Button Icon Background', + subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.', + type: 'color' + }), Header('Bluetooth'), Option({ opt: options.theme.bar.buttons.bluetooth.background, title: 'Background', type: 'color' }), Option({ opt: options.theme.bar.buttons.bluetooth.hover, title: 'Hover', type: 'color' }), Option({ opt: options.theme.bar.buttons.bluetooth.text, title: 'Text', type: 'color' }), Option({ opt: options.theme.bar.buttons.bluetooth.icon, title: 'Icon', type: 'color' }), + Option({ + opt: options.theme.bar.buttons.bluetooth.icon_background, + title: 'Button Icon Background', + subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.', + type: 'color' + }), Header('System Tray'), Option({ opt: options.theme.bar.buttons.systray.background, title: 'Background', type: 'color' }), @@ -77,6 +114,12 @@ export const BarTheme = () => { Option({ opt: options.theme.bar.buttons.battery.hover, title: 'Hover', type: 'color' }), Option({ opt: options.theme.bar.buttons.battery.text, title: 'Text', type: 'color' }), Option({ opt: options.theme.bar.buttons.battery.icon, title: 'Icon', type: 'color' }), + Option({ + opt: options.theme.bar.buttons.battery.icon_background, + title: 'Button Icon Background', + subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.', + type: 'color' + }), Header('Clock'), Option({ opt: options.theme.bar.buttons.clock.background, title: 'Background', type: 'color' }), @@ -89,6 +132,12 @@ export const BarTheme = () => { Option({ opt: options.theme.bar.buttons.notifications.hover, title: 'Hover', type: 'color' }), Option({ opt: options.theme.bar.buttons.notifications.total, title: 'Notification Count', type: 'color' }), Option({ opt: options.theme.bar.buttons.notifications.icon, title: 'Icon', type: 'color' }), + Option({ + opt: options.theme.bar.buttons.notifications.icon_background, + title: 'Button Icon Background', + subtitle: 'Applies a background color to the icon section of the button.\nRequires \'split\' button styling.', + type: 'color' + }), ] }) }) diff --git a/widget/settings/shared/FileChooser.ts b/widget/settings/shared/FileChooser.ts index 35d9854..2acdb25 100644 --- a/widget/settings/shared/FileChooser.ts +++ b/widget/settings/shared/FileChooser.ts @@ -3,6 +3,10 @@ import Gio from "gi://Gio" import { bash, Notify } from "lib/utils"; import icons from "lib/icons" +const whiteListedThemeProp = [ + "theme.bar.buttons.style" +]; + export const saveFileDialog = (filePath: string, themeOnly: boolean): void => { const original_file_path = filePath; @@ -25,7 +29,10 @@ export const saveFileDialog = (filePath: string, themeOnly: boolean): void => { for (let key in jsonObject) { if (typeof jsonObject[key] === 'string' && hexColorPattern.test(jsonObject[key])) { filteredObject[key] = jsonObject[key]; + } else if (whiteListedThemeProp.includes(key)) { + filteredObject[key] = jsonObject[key]; } + } return filteredObject; @@ -37,6 +44,11 @@ export const saveFileDialog = (filePath: string, themeOnly: boolean): void => { let filteredObject = {}; for (let key in jsonObject) { + // do not add key-value pair if its in whiteListedThemeProp + if (whiteListedThemeProp.includes(key)) { + continue; + } + if (!(typeof jsonObject[key] === 'string' && hexColorPattern.test(jsonObject[key]))) { filteredObject[key] = jsonObject[key]; } @@ -162,9 +174,12 @@ export const importFiles = (themeOnly: boolean = false): void => { const filterConfigForThemeOnly = (config: object) => { let filteredConfig = {}; + for (let key in config) { if (typeof config[key] === 'string' && hexColorPattern.test(config[key])) { filteredConfig[key] = config[key]; + } else if (whiteListedThemeProp.includes(key)) { + filteredConfig[key] = config[key]; } } return filteredConfig; @@ -173,6 +188,10 @@ export const importFiles = (themeOnly: boolean = false): void => { const filterConfigForNonTheme = (config: object) => { let filteredConfig = {}; for (let key in config) { + // do not add key-value pair if its in whiteListedThemeProp + if (whiteListedThemeProp.includes(key)) { + continue; + } if (!(typeof config[key] === 'string' && hexColorPattern.test(config[key]))) { filteredConfig[key] = config[key]; }