diff --git a/lib/types/options.d.ts b/lib/types/options.d.ts index e733817..6c913f1 100644 --- a/lib/types/options.d.ts +++ b/lib/types/options.d.ts @@ -14,6 +14,8 @@ export type RecursiveOptionsObject = { [key: string]: RecursiveOptionsObject | Opt | Opt; }; +export type BarLocation = 'top' | 'bottom'; + export type Unit = 'imperial' | 'metric'; export type PowerOptions = 'sleep' | 'reboot' | 'logout' | 'shutdown'; export type NotificationAnchor = diff --git a/modules/bar/Bar.ts b/modules/bar/Bar.ts index a681f6f..7898985 100644 --- a/modules/bar/Bar.ts +++ b/modules/bar/Bar.ts @@ -36,6 +36,7 @@ import { Attribute, Child } from 'lib/types/widget.js'; import Window from 'types/widgets/window.js'; const { layouts } = options.bar; +const { location } = options.theme.bar; export type BarWidget = keyof typeof widget; @@ -252,7 +253,7 @@ export const Bar = (() => { class_name: 'bar', monitor, visible: true, - anchor: ['top', 'left', 'right'], + anchor: location.bind('value').as((ln) => [ln, 'left', 'right']), exclusivity: 'exclusive', layer: Utils.merge( [options.theme.bar.layer.bind('value'), options.tear.bind('value')], diff --git a/modules/menus/DropdownMenu.ts b/modules/menus/DropdownMenu.ts deleted file mode 100644 index 52d5200..0000000 --- a/modules/menus/DropdownMenu.ts +++ /dev/null @@ -1,191 +0,0 @@ -const hyprland = await Service.import('hyprland'); -import { DropdownMenuProps } from 'lib/types/dropdownmenu'; -import { Attribute, Child, Exclusivity, GtkWidget } from 'lib/types/widget'; -import { bash } from 'lib/utils'; -import { Widget as TWidget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs'; -import { Monitor } from 'types/service/hyprland'; -import Box from 'types/widgets/box'; -import EventBox from 'types/widgets/eventbox'; -import Revealer from 'types/widgets/revealer'; -import Window from 'types/widgets/window'; - -type NestedRevealer = Revealer, unknown>; -type NestedBox = Box; -type NestedEventBox = EventBox; - -export const Padding = (name: string): EventBox, Attribute> => - Widget.EventBox({ - hexpand: true, - vexpand: true, - can_focus: true, - child: Widget.Box(), - setup: (w) => w.on('button-press-event', () => App.toggleWindow(name)), - }); - -const moveBoxToCursor = (self: T, fixed: boolean): void => { - if (fixed) { - return; - } - - globalMousePos.connect('changed', async ({ value }) => { - const curHyprlandMonitor = hyprland.monitors.find((m) => m.id === hyprland.active.monitor.id); - const dropdownWidth = self.child.get_allocation().width; - - let hyprScaling = 1; - try { - const monitorInfo = await bash('hyprctl monitors -j'); - const parsedMonitorInfo = JSON.parse(monitorInfo); - - const foundMonitor = parsedMonitorInfo.find( - (monitor: Monitor) => monitor.id === hyprland.active.monitor.id, - ); - hyprScaling = foundMonitor?.scale || 1; - } catch (error) { - console.error(`Error parsing hyprland monitors: ${error}`); - } - - let monWidth = curHyprlandMonitor?.width; - let monHeight = curHyprlandMonitor?.height; - - if (monWidth === undefined || monHeight === undefined || hyprScaling === undefined) { - return; - } - - // If GDK Scaling is applied, then get divide width by scaling - // to get the proper coordinates. - // Ex: On a 2860px wide monitor... if scaling is set to 2, then the right - // end of the monitor is the 1430th pixel. - const gdkScale = Utils.exec('bash -c "echo $GDK_SCALE"'); - - if (/^\d+(.\d+)?$/.test(gdkScale)) { - const scale = parseFloat(gdkScale); - monWidth = monWidth / scale; - monHeight = monHeight / scale; - } else { - monWidth = monWidth / hyprScaling; - monHeight = monHeight / hyprScaling; - } - - // If monitor is vertical (transform = 1 || 3) swap height and width - const isVertical = curHyprlandMonitor?.transform !== undefined ? curHyprlandMonitor.transform % 2 !== 0 : false; - - if (isVertical) { - [monWidth, monHeight] = [monHeight, monWidth]; - } - - let marginRight = monWidth - dropdownWidth / 2; - marginRight = fixed ? marginRight - monWidth / 2 : marginRight - value[0]; - let marginLeft = monWidth - dropdownWidth - marginRight; - - const minimumMargin = 0; - - if (marginRight < minimumMargin) { - marginRight = minimumMargin; - marginLeft = monWidth - dropdownWidth - minimumMargin; - } - - if (marginLeft < minimumMargin) { - marginLeft = minimumMargin; - marginRight = monWidth - dropdownWidth - minimumMargin; - } - - const marginTop = 45; - const marginBottom = monHeight - marginTop; - self.set_margin_left(marginLeft); - self.set_margin_right(marginRight); - self.set_margin_bottom(marginBottom); - }); -}; - -// NOTE: We make the window visible for 2 seconds (on startup) so the child -// elements can allocat their proper dimensions. -// Otherwise the width that we rely on for menu positioning is set improperly -// for the first time we open a menu of each type. -const initRender = Variable(true); - -setTimeout(() => { - initRender.value = false; -}, 2000); - -export default ({ - name, - child, - transition, - exclusivity = 'ignore' as Exclusivity, - fixed = false, - ...props -}: DropdownMenuProps): Window => - Widget.Window({ - name, - class_names: [name, 'dropdown-menu'], - setup: (w) => w.keybind('Escape', () => App.closeWindow(name)), - visible: initRender.bind('value'), - keymode: 'on-demand', - exclusivity, - layer: 'top', - anchor: ['top', 'left'], - child: Widget.EventBox({ - class_name: 'parent-event', - on_primary_click: () => App.closeWindow(name), - on_secondary_click: () => App.closeWindow(name), - child: Widget.Box({ - class_name: 'top-eb', - vertical: true, - children: [ - Widget.EventBox({ - class_name: 'mid-eb event-top-padding-static', - hexpand: true, - vexpand: false, - can_focus: false, - child: Widget.Box(), - setup: (w) => { - w.on('button-press-event', () => App.toggleWindow(name)); - w.set_margin_top(1); - }, - }), - Widget.EventBox({ - class_name: 'mid-eb event-top-padding', - hexpand: true, - vexpand: false, - can_focus: false, - child: Widget.Box(), - setup: (w) => { - w.on('button-press-event', () => App.toggleWindow(name)); - w.set_margin_top(1); - }, - }), - Widget.EventBox({ - class_name: 'in-eb menu-event-box', - on_primary_click: () => { - return true; - }, - on_secondary_click: () => { - return true; - }, - setup: (self) => { - moveBoxToCursor(self, fixed); - }, - child: Widget.Box({ - class_name: 'dropdown-menu-container', - css: 'padding: 1px; margin: -1px;', - child: Widget.Revealer({ - revealChild: false, - setup: (self) => - self.hook(App, (_, wname, visible) => { - if (wname === name) self.reveal_child = visible; - }), - transition, - transitionDuration: 350, - child: Widget.Box({ - class_name: 'dropdown-menu-container', - can_focus: true, - children: [child], - }), - }), - }), - }), - ], - }), - }), - ...props, - }); diff --git a/modules/menus/audio/index.ts b/modules/menus/audio/index.ts index 560a094..5bf317d 100644 --- a/modules/menus/audio/index.ts +++ b/modules/menus/audio/index.ts @@ -1,5 +1,5 @@ import Window from 'types/widgets/window.js'; -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; import { activeDevices } from './active/index.js'; import { availableDevices } from './available/index.js'; import { Attribute, Child } from 'lib/types/widget.js'; diff --git a/modules/menus/bluetooth/index.ts b/modules/menus/bluetooth/index.ts index 6a1a56c..3eb722e 100644 --- a/modules/menus/bluetooth/index.ts +++ b/modules/menus/bluetooth/index.ts @@ -1,5 +1,5 @@ import Window from 'types/widgets/window.js'; -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; import { Devices } from './devices/index.js'; import { Attribute, Child } from 'lib/types/widget.js'; diff --git a/modules/menus/calendar/index.ts b/modules/menus/calendar/index.ts index b0c18db..4ff2525 100644 --- a/modules/menus/calendar/index.ts +++ b/modules/menus/calendar/index.ts @@ -1,4 +1,4 @@ -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; import { TimeWidget } from './time/index.js'; import { CalendarWidget } from './calendar.js'; import { WeatherWidget } from './weather/index.js'; diff --git a/modules/menus/dashboard/index.ts b/modules/menus/dashboard/index.ts index 971a3ed..ea37628 100644 --- a/modules/menus/dashboard/index.ts +++ b/modules/menus/dashboard/index.ts @@ -1,4 +1,4 @@ -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; import { Profile } from './profile/index.js'; import { Shortcuts } from './shortcuts/index.js'; import { Controls } from './controls/index.js'; diff --git a/modules/menus/energy/index.ts b/modules/menus/energy/index.ts index 3c41940..86c898b 100644 --- a/modules/menus/energy/index.ts +++ b/modules/menus/energy/index.ts @@ -1,4 +1,4 @@ -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; import { EnergyProfiles } from './profiles/index.js'; import { Brightness } from './brightness/index.js'; import { Attribute, Child } from 'lib/types/widget.js'; diff --git a/modules/menus/media/index.ts b/modules/menus/media/index.ts index c2dfa0e..ebc45ae 100644 --- a/modules/menus/media/index.ts +++ b/modules/menus/media/index.ts @@ -1,5 +1,5 @@ import Window from 'types/widgets/window.js'; -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; import { Media } from './media.js'; import { Attribute, Child } from 'lib/types/widget.js'; diff --git a/modules/menus/network/index.ts b/modules/menus/network/index.ts index b9bda88..d0fb9ff 100644 --- a/modules/menus/network/index.ts +++ b/modules/menus/network/index.ts @@ -1,5 +1,5 @@ import Window from 'types/widgets/window.js'; -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; import { Ethernet } from './ethernet/index.js'; import { Wifi } from './wifi/index.js'; import { Attribute, Child } from 'lib/types/widget.js'; diff --git a/modules/menus/notifications/index.ts b/modules/menus/notifications/index.ts index 3a00006..ae2b151 100644 --- a/modules/menus/notifications/index.ts +++ b/modules/menus/notifications/index.ts @@ -1,5 +1,5 @@ import { Notification } from 'types/service/notifications.js'; -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; const notifs = await Service.import('notifications'); import { Controls } from './controls/index.js'; import { NotificationCard } from './notification/index.js'; diff --git a/modules/menus/power/index.ts b/modules/menus/power/index.ts index e10b0a7..394cd77 100644 --- a/modules/menus/power/index.ts +++ b/modules/menus/power/index.ts @@ -1,5 +1,5 @@ import { Action } from 'lib/types/power.js'; -import PopupWindow from '../PopupWindow.js'; +import PopupWindow from '../shared/popup/index.js'; import powermenu from './helpers/actions.js'; import icons from '../../icons/index.js'; import Window from 'types/widgets/window.js'; diff --git a/modules/menus/power/verification.ts b/modules/menus/power/verification.ts index 0f10b5f..a71f46b 100644 --- a/modules/menus/power/verification.ts +++ b/modules/menus/power/verification.ts @@ -1,5 +1,5 @@ import Window from 'types/widgets/window.js'; -import PopupWindow from '../PopupWindow.js'; +import PopupWindow from '../shared/popup/index.js'; import powermenu from './helpers/actions.js'; import { Attribute, Child } from 'lib/types/widget.js'; diff --git a/modules/menus/powerDropdown/index.ts b/modules/menus/powerDropdown/index.ts index 56ee0a8..8ebfee4 100644 --- a/modules/menus/powerDropdown/index.ts +++ b/modules/menus/powerDropdown/index.ts @@ -1,5 +1,5 @@ import Window from 'types/widgets/window.js'; -import DropdownMenu from '../DropdownMenu.js'; +import DropdownMenu from '../shared/dropdown/index.js'; import { PowerButton } from './button.js'; import { Attribute, Child } from 'lib/types/widget.js'; diff --git a/modules/menus/shared/dropdown/eventBoxes/index.ts b/modules/menus/shared/dropdown/eventBoxes/index.ts new file mode 100644 index 0000000..727610d --- /dev/null +++ b/modules/menus/shared/dropdown/eventBoxes/index.ts @@ -0,0 +1,33 @@ +import { Attribute, BoxWidget } from 'lib/types/widget'; +import EventBox from 'types/widgets/eventbox'; +import { BarLocation } from 'lib/types/options'; + +const createEventBox = (className: string, windowName: string): EventBox => { + return Widget.EventBox({ + class_name: className, + hexpand: true, + vexpand: false, + can_focus: false, + child: Widget.Box(), + setup: (w) => { + w.on('button-press-event', () => App.toggleWindow(windowName)); + }, + }); +}; + +export const barEventMargins = ( + windowName: string, + location: BarLocation = 'top', +): [EventBox, EventBox] => { + if (location === 'top') { + return [ + createEventBox('mid-eb event-top-padding-static', windowName), + createEventBox('mid-eb event-top-padding', windowName), + ]; + } else { + return [ + createEventBox('mid-eb event-bottom-padding', windowName), + createEventBox('mid-eb event-bottom-padding-static', windowName), + ]; + } +}; diff --git a/modules/menus/shared/dropdown/index.ts b/modules/menus/shared/dropdown/index.ts new file mode 100644 index 0000000..56bd97b --- /dev/null +++ b/modules/menus/shared/dropdown/index.ts @@ -0,0 +1,99 @@ +import options from 'options'; +import { DropdownMenuProps } from 'lib/types/dropdownmenu'; +import { Attribute, Child, Exclusivity } from 'lib/types/widget'; +import Window from 'types/widgets/window'; +import { moveBoxToCursor } from './locationHandler/index'; +import { barEventMargins } from './eventBoxes/index'; + +const { location } = options.theme.bar; + +// NOTE: We make the window visible for 2 seconds (on startup) so the child +// elements can allocat their proper dimensions. +// Otherwise the width that we rely on for menu positioning is set improperly +// for the first time we open a menu of each type. +const initRender = Variable(true); + +setTimeout(() => { + initRender.value = false; +}, 2000); + +export default ({ + name, + child, + transition, + exclusivity = 'ignore' as Exclusivity, + fixed = false, + ...props +}: DropdownMenuProps): Window => + Widget.Window({ + name, + class_names: [name, 'dropdown-menu'], + setup: (w) => w.keybind('Escape', () => App.closeWindow(name)), + visible: initRender.bind('value'), + keymode: 'on-demand', + exclusivity, + layer: 'top', + anchor: location.bind('value').as((ln) => [ln, 'left']), + child: Widget.EventBox({ + class_name: 'parent-event', + on_primary_click: () => App.closeWindow(name), + on_secondary_click: () => App.closeWindow(name), + child: Widget.Box({ + class_name: 'top-eb', + vertical: true, + children: [ + Widget.Box({ + className: 'event-box-container', + children: location.bind('value').as((lcn) => { + if (lcn === 'top') { + return barEventMargins(name); + } else { + return []; + } + }), + }), + Widget.EventBox({ + class_name: 'in-eb menu-event-box', + on_primary_click: () => { + return true; + }, + on_secondary_click: () => { + return true; + }, + setup: (self) => { + moveBoxToCursor(self, fixed); + }, + child: Widget.Box({ + class_name: 'dropdown-menu-container', + css: 'padding: 1px; margin: -1px;', + child: Widget.Revealer({ + revealChild: false, + setup: (self) => + self.hook(App, (_, wname, visible) => { + if (wname === name) self.reveal_child = visible; + }), + transition, + transitionDuration: 350, + child: Widget.Box({ + class_name: 'dropdown-menu-container', + can_focus: true, + children: [child], + }), + }), + }), + }), + Widget.Box({ + className: 'event-box-container', + children: location.bind('value').as((lcn) => { + if (lcn === 'bottom') { + return barEventMargins(name); + } else { + return []; + } + }), + }), + ], + }), + }), + ...props, + }); diff --git a/modules/menus/shared/dropdown/locationHandler/index.ts b/modules/menus/shared/dropdown/locationHandler/index.ts new file mode 100644 index 0000000..71752a7 --- /dev/null +++ b/modules/menus/shared/dropdown/locationHandler/index.ts @@ -0,0 +1,95 @@ +const hyprland = await Service.import('hyprland'); + +import { bash } from 'lib/utils'; +import { Widget as TWidget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs'; +import { Monitor } from 'types/service/hyprland'; +import Box from 'types/widgets/box'; +import EventBox from 'types/widgets/eventbox'; +import Revealer from 'types/widgets/revealer'; + +type NestedRevealer = Revealer, unknown>; +type NestedBox = Box; +type NestedEventBox = EventBox; + +const { location } = options.theme.bar; + +export const moveBoxToCursor = (self: T, fixed: boolean): void => { + if (fixed) { + return; + } + + globalMousePos.connect('changed', async ({ value }) => { + const curHyprlandMonitor = hyprland.monitors.find((m) => m.id === hyprland.active.monitor.id); + const dropdownWidth = self.child.get_allocation().width; + const dropdownHeight = self.child.get_allocation().height; + + let hyprScaling = 1; + try { + const monitorInfo = await bash('hyprctl monitors -j'); + const parsedMonitorInfo = JSON.parse(monitorInfo); + + const foundMonitor = parsedMonitorInfo.find( + (monitor: Monitor) => monitor.id === hyprland.active.monitor.id, + ); + hyprScaling = foundMonitor?.scale || 1; + } catch (error) { + console.error(`Error parsing hyprland monitors: ${error}`); + } + + let monWidth = curHyprlandMonitor?.width; + let monHeight = curHyprlandMonitor?.height; + + if (monWidth === undefined || monHeight === undefined || hyprScaling === undefined) { + return; + } + + // If GDK Scaling is applied, then get divide width by scaling + // to get the proper coordinates. + // Ex: On a 2860px wide monitor... if scaling is set to 2, then the right + // end of the monitor is the 1430th pixel. + const gdkScale = Utils.exec('bash -c "echo $GDK_SCALE"'); + + if (/^\d+(.\d+)?$/.test(gdkScale)) { + const scale = parseFloat(gdkScale); + monWidth = monWidth / scale; + monHeight = monHeight / scale; + } else { + monWidth = monWidth / hyprScaling; + monHeight = monHeight / hyprScaling; + } + + // If monitor is vertical (transform = 1 || 3) swap height and width + const isVertical = curHyprlandMonitor?.transform !== undefined ? curHyprlandMonitor.transform % 2 !== 0 : false; + + if (isVertical) { + [monWidth, monHeight] = [monHeight, monWidth]; + } + + let marginRight = monWidth - dropdownWidth / 2; + marginRight = fixed ? marginRight - monWidth / 2 : marginRight - value[0]; + let marginLeft = monWidth - dropdownWidth - marginRight; + + const minimumMargin = 0; + + if (marginRight < minimumMargin) { + marginRight = minimumMargin; + marginLeft = monWidth - dropdownWidth - minimumMargin; + } + + if (marginLeft < minimumMargin) { + marginLeft = minimumMargin; + marginRight = monWidth - dropdownWidth - minimumMargin; + } + + self.set_margin_left(marginLeft); + self.set_margin_right(marginRight); + + if (location.value === 'top') { + self.set_margin_top(0); + self.set_margin_bottom(monHeight); + } else { + self.set_margin_bottom(0); + self.set_margin_top(monHeight - dropdownHeight); + } + }); +}; diff --git a/modules/menus/PopupWindow.ts b/modules/menus/shared/popup/index.ts similarity index 100% rename from modules/menus/PopupWindow.ts rename to modules/menus/shared/popup/index.ts diff --git a/options.ts b/options.ts index 0a3ca83..14e2dfd 100644 --- a/options.ts +++ b/options.ts @@ -12,6 +12,7 @@ import { KbIcon, KbLabelType } from 'lib/types/customModules/kbLayout'; import { ActiveWsIndicator, BarButtonStyles, + BarLocation, NotificationAnchor, OSDAnchor, OSDOrientation, @@ -145,6 +146,7 @@ const options = mkOptions(OPTIONS, { bar: { scaling: opt(100), floating: opt(false), + location: opt('top'), layer: opt('top'), margin_top: opt('0.5em'), opacity: opt(100), @@ -154,6 +156,7 @@ const options = mkOptions(OPTIONS, { outer_spacing: opt('1.6em'), label_spacing: opt('0.5em'), transparent: opt(false), + dropdownGap: opt('2.9em'), background: opt(colors.crust), buttons: { style: opt('default'), diff --git a/scss/style/menus/menu.scss b/scss/style/menus/menu.scss index 89ebf53..349169a 100644 --- a/scss/style/menus/menu.scss +++ b/scss/style/menus/menu.scss @@ -1,257 +1,256 @@ .menu-slider { - trough { - border-radius: 0.3rem; - background: $surface0; - - highlight, - progress { - background: $peach; - border-radius: 0.3rem; - } - } - - slider { - box-shadow: none; - background-color: transparent; - min-height: 0.6rem; - min-width: 0.6rem; - border: 0rem solid transparent; - border-radius: 0.3rem; - } - - &:hover { trough { - background: $surface0; + border-radius: 0.3rem; + background: $surface0; + + highlight, + progress { + background: $peach; + border-radius: 0.3rem; + } } slider { - background: $overlay0; - box-shadow: none; + box-shadow: none; + background-color: transparent; + min-height: 0.6rem; + min-width: 0.6rem; + border: 0rem solid transparent; + border-radius: 0.3rem; + } + + &:hover { + trough { + background: $surface0; + } + + slider { + background: $overlay0; + box-shadow: none; + } } - } } .menu-switch { - font-size: 1.3em; - background-color: $surface0; - border-radius: 0.2em; - - &:checked { - background: $sky; - } - - trough { - - highlight, - progress { - background-color: $peach; - border-radius: 0.3em; - } - } - - slider { - box-shadow: none; - background-color: $overlay0; - min-height: 1em; - min-width: 1em; - border: 0em solid transparent; + font-size: 1.3em; + background-color: $surface0; border-radius: 0.2em; - margin: 0.1em 0.15em; - } - &:hover { + &:checked { + background: $sky; + } + trough { - background: $surface0; + highlight, + progress { + background-color: $peach; + border-radius: 0.3em; + } } slider { - background: $overlay0; - box-shadow: none; + box-shadow: none; + background-color: $overlay0; + min-height: 1em; + min-width: 1em; + border: 0em solid transparent; + border-radius: 0.2em; + margin: 0.1em 0.15em; } - } - &:active { - background-color: $sky; - } + &:hover { + trough { + background: $surface0; + } + + slider { + background: $overlay0; + box-shadow: none; + } + } + + &:active { + background-color: $sky; + } } .menu-separator { - min-height: .1rem; - margin: .6rem 0rem; - background: $surface1; + min-height: 0.1rem; + margin: 0.6rem 0rem; + background: $surface1; } .menu-items { - background: $crust; - border: $bar-menus-border-size solid $bar-menus-border-color; - border-radius: $bar-menus-border-radius; - color: $text; + background: $crust; + border: $bar-menus-border-size solid $bar-menus-border-color; + border-radius: $bar-menus-border-radius; + color: $text; } .menu-items-container { - border-radius: 0.4em; - font-size: 1.3em; + border-radius: 0.4em; + font-size: 1.3em; } .menu-section-container { - margin: 1em 0em; + margin: 1em 0em; - .menu-label { - color: $text; - font-size: 1.1em; - font-weight: bold; - } + .menu-label { + color: $text; + font-size: 1.1em; + font-weight: bold; + } - .menu-label-container { - background: $base; - border-radius: $bar-menus-card_radius; - border-bottom-left-radius: 0em; - border-bottom-right-radius: 0em; - margin: 0em 1em; - min-height: 2em; - } + .menu-label-container { + background: $base; + border-radius: $bar-menus-card_radius; + border-bottom-left-radius: 0em; + border-bottom-right-radius: 0em; + margin: 0em 1em; + min-height: 2em; + } - &:first-child { - margin-bottom: 0em; - } + &:first-child { + margin-bottom: 0em; + } - &:last-child { - margin-top: 0em; - } + &:last-child { + margin-top: 0em; + } - &:nth-child(2) { - margin-top: 1em; - } + &:nth-child(2) { + margin-top: 1em; + } - .menu-items-section { - background: $base; - border-radius: $bar-menus-card_radius; - border-top-left-radius: 0em; - border-top-right-radius: 0em; - padding: 0.9em; - margin: 0em 1em; - } + .menu-items-section { + background: $base; + border-radius: $bar-menus-card_radius; + border-top-left-radius: 0em; + border-top-right-radius: 0em; + padding: 0.9em; + margin: 0em 1em; + } } .menu-active { - font-size: 0.9em; - font-weight: bold; - margin: 0rem 1em; - margin-bottom: 0.9em; + font-size: 0.9em; + font-weight: bold; + margin: 0rem 1em; + margin-bottom: 0.9em; } .menu-active-container { - &:first-child { - margin-bottom: 0.5em; - } + &:first-child { + margin-bottom: 0.5em; + } } .menu-active-button { - padding: 0.1em; - margin-bottom: -0.2em; + padding: 0.1em; + margin-bottom: -0.2em; - .menu-active-icon { - font-size: 1.4em; - font-weight: bold; + .menu-active-icon { + font-size: 1.4em; + font-weight: bold; + } - } + &.muted image { + color: $maroon; + } - &.muted image { - color: $maroon; - } - - &:hover image { - color: $maroon; - } + &:hover image { + color: $maroon; + } } .menu-active-percentage { - font-size: 0.9em; - min-width: 2.5em; - font-weight: bold; + font-size: 0.9em; + min-width: 2.5em; + font-weight: bold; } .menu-active-slider { - margin-left: 1rem; - margin-right: 1.5rem; + margin-left: 1rem; + margin-right: 1.5rem; } .menu-active-slider * { - min-height: 0.85em; - border-radius: .2em; + min-height: 0.85em; + border-radius: 0.2em; } .menu-slider-container { - margin-bottom: .7rem; + margin-bottom: 0.7rem; } .menu-label-dim { - color: $overlay0; - margin-right: 1rem; - font-size: 1em; - font-weight: bold; + color: $overlay0; + margin-right: 1rem; + font-size: 1em; + font-weight: bold; } .menu-icon-button { - &:hover { - color: $surface2; - } + &:hover { + color: $surface2; + } } .menu-dropdown-label-container { - background: $base; - border-radius: 0.4em; + background: $base; + border-radius: 0.4em; } .menu-button { - margin-bottom: .4em; + margin-bottom: 0.4em; } .menu-button-name { - font-size: 0.95em; - font-weight: bold; - margin-left: 0.5em; - margin-right: 1.2rem; + font-size: 0.95em; + font-weight: bold; + margin-left: 0.5em; + margin-right: 1.2rem; } .menu-button-icon { - font-size: 1.3em; - font-weight: bold; - margin-right: .5rem; + font-size: 1.3em; + font-weight: bold; + margin-right: 0.5rem; } .menu-item-box { - margin-bottom: 0.5rem; + margin-bottom: 0.5rem; } .dropdown-menu-container { - min-height: 10em; + min-height: 10em; } .menu-label { - margin: 0.5em 1em; - color: $sky; + margin: 0.5em 1em; + color: $sky; } -.event-top-padding-static * { - min-height: 0em; - margin-top: 2.8em; +.event-box-container { + min-height: 0em; + margin-top: $bar-dropdownGap; } .event-top-padding * { - min-height: 0em; - margin-top: if($bar-floating, $bar-margin_top, 0); + min-height: 0em; + margin-top: if($bar-floating and $bar-location == 'top', $bar-margin_top, 0); + margin-bottom: if($bar-floating and $bar-location == 'bottom', $bar-margin_bottom, 0); } @keyframes spin { - to { - -gtk-icon-transform: rotate(1turn); - } + to { + -gtk-icon-transform: rotate(1turn); + } } image.spinning { - animation-name: spin; - animation-duration: 1s; - animation-timing-function: linear; - animation-iteration-count: infinite; + animation-name: spin; + animation-duration: 1s; + animation-timing-function: linear; + animation-iteration-count: infinite; } diff --git a/widget/settings/pages/config/bar/index.ts b/widget/settings/pages/config/bar/index.ts index f20c7b1..ef685c7 100644 --- a/widget/settings/pages/config/bar/index.ts +++ b/widget/settings/pages/config/bar/index.ts @@ -29,6 +29,17 @@ export const BarSettings = (): Scrollable => { }, 'bar-layout-input', ), + Option({ + opt: options.theme.bar.floating, + title: 'Floating Bar', + type: 'boolean', + }), + Option({ + opt: options.theme.bar.location, + title: 'Location', + type: 'enum', + enums: ['top', 'bottom'], + }), /* ****************************** @@ -69,11 +80,6 @@ export const BarSettings = (): Scrollable => { title: 'Button Radius', type: 'string', }), - Option({ - opt: options.theme.bar.floating, - title: 'Floating Bar', - type: 'boolean', - }), Option({ opt: options.theme.bar.layer, title: 'Layer', @@ -81,6 +87,12 @@ export const BarSettings = (): Scrollable => { subtitle: 'Layer determines the Z index of your bar.', enums: ['top', 'bottom', 'overlay', 'background'], }), + Option({ + opt: options.theme.bar.dropdownGap, + title: 'Dropdown Gap', + subtitle: 'The gap between the dropdown and the bar', + type: 'string', + }), Option({ opt: options.theme.bar.margin_top, title: 'Margin Top',