Implement custom icons per workspace. (#261)

* Implement custom icons per workspace.

* Finish custom workspace icon implementation

* Remove unsupported color definition.
This commit is contained in:
Jas Singh
2024-09-15 15:19:32 -07:00
committed by GitHub
parent 8c2537b917
commit f09ffa7699
12 changed files with 437 additions and 360 deletions

View File

@@ -11,21 +11,26 @@
<br/>
# HyprPanel 🚀
A panel built for Hyprland with [AGS](https://github.com/Aylur/ags)
![HyprPanel](./assets/HyprPanel.png)
## Installation
The [HyprPanel Wiki](https://hyprpanel.com/getting_started/installation.html) contains in depth instructions for installing the panel and all of its dependencies. The instructions below are general instructions for installing the panel.
## Requirements
Bun
```sh
curl -fsSL https://bun.sh/install | bash && \
sudo ln -s $HOME/.bun/bin/bun /usr/local/bin/bun
```
Additional dependencies:
```sh
pipewire
libgtop
@@ -45,6 +50,7 @@ gnome-bluetooth-3.0
```
Optional Dependencies:
```sh
## Used for Tracking GPU Usage in your Dashboard (NVidia only)
python
@@ -58,11 +64,13 @@ pacman-contrib
```
Arch (pacman):
```bash
sudo pacman -S pipewire libgtop bluez bluez-utils btop networkmanager dart-sass wl-clipboard brightnessctl swww python gnome-bluetooth-3.0 pacman-contrib
```
Arch (AUR):
```bash
yay -S grimblast-git gpu-screen-recorder hyprpicker matugen-bin python-gpustat aylurs-gtk-shell-git
```
@@ -72,32 +80,43 @@ For NixOS/Home-Manager, see [NixOS & Home-Manager instructions](#nixos--home-man
## Instructions
### AGS
Once everything is installed you need to put the contents of this repo in `~/.config/ags`.
If you already have something in `~/.config/ags`, it's recommended that you back it up with:
```bash
mv $HOME/.config/ags $HOME/.config/ags.bkup
```
Otherwise you can use this command to install the panel:
```bash
git clone https://github.com/Jas-SinghFSU/HyprPanel.git && \
ln -s $(pwd)/HyprPanel $HOME/.config/ags
```
### Nerd Fonts
Additionally, you need to ensure that you have a [Nerd Font](https://www.nerdfonts.com/font-downloads) installed for your icons to render properly.
### Launch the panel
Afterwards you can run the panel with the following command in your terminal:
```bash
ags
```
Or you can add it to your Hyprland config (hyprland.conf) to auto-start with:
```bash
exec-once = ags
```
### NixOS & Home-Manager
Alternatively, if you're using NixOS and/or Home-Manager, you can setup AGS using the provided Nix Flake. First, add the repository to your Flake's inputs, and enable the overlay.
```nix
# flake.nix
@@ -175,6 +194,7 @@ The panel is automatically scaled based on your font size in `Configuration > Ge
### Specifying bar layouts per monitor
To specify layouts for each monitor you can create a JSON object such as:
```JSON
{
"0": {
@@ -229,19 +249,21 @@ To specify layouts for each monitor you can create a JSON object such as:
```
Where each monitor is defined by its index (0, 1, 2 in this case) and each section (left, middle, right) contains one or more of the following modules:
```js
"battery"
"dashboard"
"workspaces"
"windowtitle"
"media"
"notifications"
"volume"
"network"
"bluetooth"
"clock"
"systray"
'battery';
'dashboard';
'workspaces';
'windowtitle';
'media';
'notifications';
'volume';
'network';
'bluetooth';
'clock';
'systray';
```
Since the text-box in the options dialog isn't sufficient, it is recommended that you create this JSON configuration in a text editor elsewhere and paste it into the layout text-box under Configuration > Bar > "Bar Layouts for Monitors".
### Additional Configuration

142
lib/constants/colors.ts Normal file
View File

@@ -0,0 +1,142 @@
export const namedColors = new Set([
'alice blue',
'antique white',
'aqua',
'aquamarine',
'azure',
'beige',
'bisque',
'black',
'blanched almond',
'blue',
'blue violet',
'brown',
'burlywood',
'cadet blue',
'chartreuse',
'chocolate',
'coral',
'cornflower blue',
'cornsilk',
'crimson',
'cyan',
'dark blue',
'dark cyan',
'dark goldenrod',
'dark gray',
'dark green',
'dark khaki',
'dark magenta',
'dark olive green',
'dark orange',
'dark orchid',
'dark red',
'dark salmon',
'dark sea green',
'dark slate blue',
'dark slate gray',
'dark turquoise',
'dark violet',
'deep pink',
'deep sky blue',
'dim gray',
'dodger blue',
'firebrick',
'floral white',
'forest green',
'fuchsia',
'gainsboro',
'ghost white',
'gold',
'goldenrod',
'gray',
'green',
'green yellow',
'honeydew',
'hot pink',
'indian red',
'indigo',
'ivory',
'khaki',
'lavender',
'lavender blush',
'lawn green',
'lemon chiffon',
'light blue',
'light coral',
'light cyan',
'light goldenrod yellow',
'light green',
'light grey',
'light pink',
'light salmon',
'light sea green',
'light sky blue',
'light slate gray',
'light steel blue',
'light yellow',
'lime',
'lime green',
'linen',
'magenta',
'maroon',
'medium aquamarine',
'medium blue',
'medium orchid',
'medium purple',
'medium sea green',
'medium slate blue',
'medium spring green',
'medium turquoise',
'medium violet red',
'midnight blue',
'mint cream',
'misty rose',
'moccasin',
'navajo white',
'navy',
'old lace',
'olive',
'olive drab',
'orange',
'orange red',
'orchid',
'pale goldenrod',
'pale green',
'pale turquoise',
'pale violet red',
'papaya whip',
'peach puff',
'peru',
'pink',
'plum',
'powder blue',
'purple',
'red',
'rosy brown',
'royal blue',
'saddle brown',
'salmon',
'sandy brown',
'sea green',
'seashell',
'sienna',
'silver',
'sky blue',
'slate blue',
'slate gray',
'snow',
'spring green',
'steel blue',
'tan',
'teal',
'thistle',
'tomato',
'turquoise',
'violet',
'wheat',
'white',
'white smoke',
'yellow',
'yellow green',
]);

View File

@@ -10,3 +10,16 @@ export type WorkspaceMap = {
export type MonitorMap = {
[key: number]: string;
};
export type WorkspaceIcons = {
[key: string]: string;
};
export type WorkspaceIconsColored = {
[key: string]: {
color: string;
icon: string;
};
};
export type WorkspaceIconMap = WorkspaceIcons | WorkspaceIconsColored;

View File

@@ -10,6 +10,7 @@ import GdkPixbuf from 'gi://GdkPixbuf';
import { NotificationArgs } from 'types/utils/notify';
import { SubstituteKeys } from './types/utils';
import { Window } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
import { namedColors } from './constants/colors';
export type Binding<T> = import('types/service').Binding<any, any, T>;
@@ -166,3 +167,25 @@ export function getPosition(pos: NotificationAnchor | OSDAnchor): ('top' | 'bott
return positionMap[pos] || ['top'];
}
export const isValidGjsColor = (color: string): boolean => {
const colorLower = color.toLowerCase().trim();
if (namedColors.has(colorLower)) {
return true;
}
const hexColorRegex = /^#(?:[a-fA-F0-9]{3,4}|[a-fA-F0-9]{6,8})$/;
const rgbRegex = /^rgb\(\s*(\d{1,3}%?\s*,\s*){2}\d{1,3}%?\s*\)$/;
const rgbaRegex = /^rgba\(\s*(\d{1,3}%?\s*,\s*){3}(0|1|0?\.\d+)\s*\)$/;
if (hexColorRegex.test(color)) {
return true;
}
if (rgbRegex.test(colorLower) || rgbaRegex.test(colorLower)) {
return true;
}
return false;
};

View File

@@ -1,20 +1,10 @@
const hyprland = await Service.import('hyprland');
import options from 'options';
import {
createThrottledScrollHandlers,
getCurrentMonitorWorkspaces,
getWorkspaceRules,
getWorkspacesForMonitor,
} from './helpers';
import { Workspace } from 'types/service/hyprland';
import { BoxWidget } from 'lib/types/widget';
import { createThrottledScrollHandlers, getCurrentMonitorWorkspaces } from './helpers';
import { BarBoxChild, SelfButton } from 'lib/types/bar';
import { occupiedWses } from './variants/occupied';
import { defaultWses } from './variants/default';
const { workspaces, monitorSpecific, workspaceMask, scroll_speed, spacing } = options.bar.workspaces;
function range(length: number, start = 1): number[] {
return Array.from({ length }, (_, i) => i + start);
}
const { workspaces, scroll_speed } = options.bar.workspaces;
const Workspaces = (monitor = -1): BarBoxChild => {
const currentMonitorWorkspaces = Variable(getCurrentMonitorWorkspaces(monitor));
@@ -23,249 +13,12 @@ const Workspaces = (monitor = -1): BarBoxChild => {
currentMonitorWorkspaces.value = getCurrentMonitorWorkspaces(monitor);
});
const renderClassnames = (
showIcons: boolean,
showNumbered: boolean,
numberedActiveIndicator: string,
i: number,
): string => {
if (showIcons) {
return `workspace-icon txt-icon bar`;
}
if (showNumbered) {
const numActiveInd = hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
}
return 'default';
};
const renderLabel = (
showIcons: boolean,
available: string,
active: string,
occupied: string,
workspaceMask: boolean,
i: number,
index: number,
): string => {
if (showIcons) {
if (hyprland.active.workspace.id === i) {
return active;
}
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
return occupied;
}
if (monitor !== -1) {
return available;
}
}
return workspaceMask ? `${index + 1}` : `${i}`;
};
const defaultWses = (): BoxWidget => {
return Widget.Box({
children: Utils.merge(
[workspaces.bind('value'), monitorSpecific.bind()],
(workspaces: number, monitorSpecific: boolean) => {
return range(workspaces || 8)
.filter((i) => {
if (!monitorSpecific) {
return true;
}
const workspaceRules = getWorkspaceRules();
return getWorkspacesForMonitor(i, workspaceRules, monitor);
})
.sort((a, b) => {
return a - b;
})
.map((i, index) => {
return Widget.Button({
class_name: 'workspace-button',
on_primary_click: () => {
hyprland.messageAsync(`dispatch workspace ${i}`);
},
child: Widget.Label({
attribute: i,
vpack: 'center',
css: spacing.bind('value').as((sp) => `margin: 0rem ${0.375 * sp}rem;`),
class_name: Utils.merge(
[
options.bar.workspaces.show_icons.bind('value'),
options.bar.workspaces.show_numbered.bind('value'),
options.bar.workspaces.numbered_active_indicator.bind('value'),
options.bar.workspaces.icons.available.bind('value'),
options.bar.workspaces.icons.active.bind('value'),
options.bar.workspaces.icons.occupied.bind('value'),
hyprland.active.workspace.bind('id'),
],
(
showIcons: boolean,
showNumbered: boolean,
numberedActiveIndicator: string,
) => {
if (showIcons) {
return `workspace-icon txt-icon bar`;
}
if (showNumbered) {
const numActiveInd =
hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
}
return 'default';
},
),
label: Utils.merge(
[
options.bar.workspaces.show_icons.bind('value'),
options.bar.workspaces.icons.available.bind('value'),
options.bar.workspaces.icons.active.bind('value'),
options.bar.workspaces.icons.occupied.bind('value'),
workspaceMask.bind('value'),
hyprland.active.workspace.bind('id'),
],
(
showIcons: boolean,
available: string,
active: string,
occupied: string,
workspaceMask: boolean,
) => {
if (showIcons) {
if (hyprland.active.workspace.id === i) {
return active;
}
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
return occupied;
}
if (monitor !== -1) {
return available;
}
}
return workspaceMask ? `${index + 1}` : `${i}`;
},
),
setup: (self) => {
self.hook(hyprland, () => {
self.toggleClassName('active', hyprland.active.workspace.id === i);
self.toggleClassName(
'occupied',
(hyprland.getWorkspace(i)?.windows || 0) > 0,
);
});
},
}),
});
});
},
),
});
};
const occupiedWses = (): BoxWidget => {
return Widget.Box({
children: Utils.merge(
[
monitorSpecific.bind('value'),
hyprland.bind('workspaces'),
workspaceMask.bind('value'),
workspaces.bind('value'),
options.bar.workspaces.show_icons.bind('value'),
options.bar.workspaces.icons.available.bind('value'),
options.bar.workspaces.icons.active.bind('value'),
options.bar.workspaces.icons.occupied.bind('value'),
options.bar.workspaces.show_numbered.bind('value'),
options.bar.workspaces.numbered_active_indicator.bind('value'),
spacing.bind('value'),
hyprland.active.workspace.bind('id'),
],
(
monitorSpecific: boolean,
wkSpaces: Workspace[],
workspaceMask: boolean,
totalWkspcs: number,
showIcons: boolean,
available: string,
active: string,
occupied: string,
showNumbered: boolean,
numberedActiveIndicator: string,
spacing: number,
activeId: number,
) => {
let allWkspcs = range(totalWkspcs || 8);
const activeWorkspaces = wkSpaces.map((w) => w.id);
const workspaceRules = getWorkspaceRules();
// Sometimes hyprland doesn't have all the monitors in the list
// so we complement it with monitors from the workspace list
const workspaceMonitorList = hyprland?.workspaces?.map((m) => ({
id: m.monitorID,
name: m.monitor,
}));
const curMonitor =
hyprland.monitors.find((m) => m.id === monitor) ||
workspaceMonitorList.find((m) => m.id === monitor);
// go through each key in workspaceRules and flatten the array
const workspacesWithRules = Object.keys(workspaceRules).reduce((acc: number[], k: string) => {
return [...acc, ...workspaceRules[k]];
}, [] as number[]);
const activesForMonitor = activeWorkspaces.filter((w) => {
if (
curMonitor &&
Object.hasOwnProperty.call(workspaceRules, curMonitor.name) &&
workspacesWithRules.includes(w)
) {
return workspaceRules[curMonitor.name].includes(w);
}
return true;
});
if (monitorSpecific) {
const wrkspcsInRange = range(totalWkspcs).filter((w) => {
return getWorkspacesForMonitor(w, workspaceRules, monitor);
});
allWkspcs = [...new Set([...activesForMonitor, ...wrkspcsInRange])];
} else {
allWkspcs = [...new Set([...allWkspcs, ...activeWorkspaces])];
}
return allWkspcs
.sort((a, b) => {
return a - b;
})
.map((i, index) => {
return Widget.Button({
class_name: 'workspace-button',
on_primary_click: () => {
hyprland.messageAsync(`dispatch workspace ${i}`);
},
child: Widget.Label({
attribute: i,
vpack: 'center',
css: `margin: 0rem ${0.375 * spacing}rem;`,
class_name: renderClassnames(showIcons, showNumbered, numberedActiveIndicator, i),
label: renderLabel(showIcons, available, active, occupied, workspaceMask, i, index),
setup: (self) => {
self.toggleClassName('active', activeId === i);
self.toggleClassName('occupied', (hyprland.getWorkspace(i)?.windows || 0) > 0);
},
}),
});
});
},
),
});
};
return {
component: Widget.Box({
class_name: 'workspaces',
child: options.bar.workspaces.hideUnoccupied
.bind('value')
.as((hideUnoccupied) => (hideUnoccupied ? occupiedWses() : defaultWses())),
.as((hideUnoccupied) => (hideUnoccupied ? occupiedWses(monitor) : defaultWses(monitor))),
}),
isVisible: true,
boxClass: 'workspaces',

View File

@@ -1,18 +1,60 @@
import { WorkspaceIconMap } from 'lib/types/workspace';
import { isValidGjsColor } from 'lib/utils';
const hyprland = await Service.import('hyprland');
const getWsIcon = (wsIconMap: WorkspaceIconMap, i: number): string => {
const iconEntry = wsIconMap[i];
if (!iconEntry) {
return `${i}`;
}
const hasIcon = typeof iconEntry === 'object' && 'icon' in iconEntry && iconEntry.icon !== '';
if (typeof iconEntry === 'string' && iconEntry !== '') {
return iconEntry;
}
if (hasIcon) {
return iconEntry.icon;
}
return `${i}`;
};
export const getWsColor = (wsIconMap: WorkspaceIconMap, i: number): string => {
const iconEntry = wsIconMap[i];
if (!iconEntry) {
return '';
}
const hasColor = typeof iconEntry === 'object' && 'color' in iconEntry && iconEntry.color !== '';
if (hasColor && isValidGjsColor(iconEntry.color)) {
return `color: ${iconEntry.color}; border-bottom-color: ${iconEntry.color};`;
}
return '';
};
export const renderClassnames = (
showIcons: boolean,
showNumbered: boolean,
numberedActiveIndicator: string,
showWsIcons: boolean,
i: number,
): string => {
if (showIcons) {
return `workspace-icon txt-icon bar`;
}
if (showNumbered) {
const numActiveInd = hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
if (showNumbered || showWsIcons) {
const numActiveInd = hyprland.active.workspace.id === i ? `${numberedActiveIndicator}` : '';
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
const className =
`workspace-number can_${numberedActiveIndicator} ` +
`${numActiveInd} ` +
`${showWsIcons ? 'txt-icon' : ''}`;
return className;
}
return 'default';
};
@@ -23,6 +65,8 @@ export const renderLabel = (
active: string,
occupied: string,
workspaceMask: boolean,
showWsIcons: boolean,
wsIconMap: WorkspaceIconMap,
i: number,
index: number,
monitor: number,
@@ -38,6 +82,8 @@ export const renderLabel = (
return available;
}
}
if (showWsIcons) {
return getWsIcon(wsIconMap, i);
}
return workspaceMask ? `${index + 1}` : `${i}`;
};

View File

@@ -3,6 +3,8 @@ import options from 'options';
import { getWorkspaceRules, getWorkspacesForMonitor } from '../helpers';
import { range } from 'lib/utils';
import { BoxWidget } from 'lib/types/widget';
import { getWsColor, renderClassnames, renderLabel } from '../utils';
import { WorkspaceIconMap } from 'lib/types/workspace';
const { workspaces, monitorSpecific, workspaceMask, spacing } = options.bar.workspaces;
export const defaultWses = (monitor: number): BoxWidget => {
@@ -30,28 +32,48 @@ export const defaultWses = (monitor: number): BoxWidget => {
child: Widget.Label({
attribute: i,
vpack: 'center',
css: spacing.bind('value').as((sp) => `margin: 0rem ${0.375 * sp}rem;`),
css: Utils.merge(
[
spacing.bind('value'),
options.bar.workspaces.showWsIcons.bind('value'),
options.bar.workspaces.workspaceIconMap.bind('value'),
options.theme.matugen.bind('value'),
],
(
sp: number,
showWsIcons: boolean,
workspaceIconMap: WorkspaceIconMap,
matugen: boolean,
) => {
return (
`margin: 0rem ${0.375 * sp}rem;` +
`${showWsIcons && !matugen ? getWsColor(workspaceIconMap, i) : ''}`
);
},
),
class_name: Utils.merge(
[
options.bar.workspaces.show_icons.bind('value'),
options.bar.workspaces.show_numbered.bind('value'),
options.bar.workspaces.numbered_active_indicator.bind('value'),
options.bar.workspaces.showWsIcons.bind('value'),
options.bar.workspaces.icons.available.bind('value'),
options.bar.workspaces.icons.active.bind('value'),
options.bar.workspaces.icons.occupied.bind('value'),
hyprland.active.workspace.bind('id'),
],
(showIcons: boolean, showNumbered: boolean, numberedActiveIndicator: string) => {
if (showIcons) {
return `workspace-icon txt-icon bar`;
}
if (showNumbered) {
const numActiveInd =
hyprland.active.workspace.id === i ? numberedActiveIndicator : '';
return `workspace-number can_${numberedActiveIndicator} ${numActiveInd}`;
}
return 'default';
(
showIcons: boolean,
showNumbered: boolean,
numberedActiveIndicator: string,
showWsIcons: boolean,
) => {
return renderClassnames(
showIcons,
showNumbered,
numberedActiveIndicator,
showWsIcons,
i,
);
},
),
label: Utils.merge(
@@ -60,6 +82,8 @@ export const defaultWses = (monitor: number): BoxWidget => {
options.bar.workspaces.icons.available.bind('value'),
options.bar.workspaces.icons.active.bind('value'),
options.bar.workspaces.icons.occupied.bind('value'),
options.bar.workspaces.workspaceIconMap.bind('value'),
options.bar.workspaces.showWsIcons.bind('value'),
workspaceMask.bind('value'),
hyprland.active.workspace.bind('id'),
],
@@ -68,20 +92,22 @@ export const defaultWses = (monitor: number): BoxWidget => {
available: string,
active: string,
occupied: string,
wsIconMap: WorkspaceIconMap,
showWsIcons: boolean,
workspaceMask: boolean,
) => {
if (showIcons) {
if (hyprland.active.workspace.id === i) {
return active;
}
if ((hyprland.getWorkspace(i)?.windows || 0) > 0) {
return occupied;
}
if (monitor !== -1) {
return available;
}
}
return workspaceMask ? `${index + 1}` : `${i}`;
return renderLabel(
showIcons,
available,
active,
occupied,
workspaceMask,
showWsIcons,
wsIconMap,
i,
index,
monitor,
);
},
),
setup: (self) => {

View File

@@ -2,9 +2,10 @@ const hyprland = await Service.import('hyprland');
import options from 'options';
import { getWorkspaceRules, getWorkspacesForMonitor } from '../helpers';
import { Workspace } from 'types/service/hyprland';
import { renderClassnames, renderLabel } from '../utils';
import { getWsColor, renderClassnames, renderLabel } from '../utils';
import { range } from 'lib/utils';
import { BoxWidget } from 'lib/types/widget';
import { WorkspaceIconMap } from 'lib/types/workspace';
const { workspaces, monitorSpecific, workspaceMask, spacing } = options.bar.workspaces;
@@ -24,6 +25,9 @@ export const occupiedWses = (monitor: number): BoxWidget => {
options.bar.workspaces.numbered_active_indicator.bind('value'),
spacing.bind('value'),
hyprland.active.workspace.bind('id'),
options.bar.workspaces.workspaceIconMap.bind('value'),
options.bar.workspaces.showWsIcons.bind('value'),
options.theme.matugen.bind('value'),
],
(
monitorSpecific: boolean,
@@ -38,6 +42,9 @@ export const occupiedWses = (monitor: number): BoxWidget => {
numberedActiveIndicator: string,
spacing: number,
activeId: number,
wsIconMap: WorkspaceIconMap,
showWsIcons: boolean,
matugen: boolean,
) => {
let allWkspcs = range(totalWkspcs || 8);
@@ -46,7 +53,10 @@ export const occupiedWses = (monitor: number): BoxWidget => {
// Sometimes hyprland doesn't have all the monitors in the list
// so we complement it with monitors from the workspace list
const workspaceMonitorList = hyprland?.workspaces?.map((m) => ({ id: m.monitorID, name: m.monitor }));
const workspaceMonitorList = hyprland?.workspaces?.map((m) => ({
id: m.monitorID,
name: m.monitor,
}));
const curMonitor =
hyprland.monitors.find((m) => m.id === monitor) ||
workspaceMonitorList.find((m) => m.id === monitor);
@@ -89,14 +99,24 @@ export const occupiedWses = (monitor: number): BoxWidget => {
child: Widget.Label({
attribute: i,
vpack: 'center',
css: `margin: 0rem ${0.375 * spacing}rem;`,
class_name: renderClassnames(showIcons, showNumbered, numberedActiveIndicator, i),
css:
`margin: 0rem ${0.375 * spacing}rem;` +
`${showWsIcons && !matugen ? getWsColor(wsIconMap, i) : ''}`,
class_name: renderClassnames(
showIcons,
showNumbered,
numberedActiveIndicator,
showWsIcons,
i,
),
label: renderLabel(
showIcons,
available,
active,
occupied,
workspaceMask,
showWsIcons,
wsIconMap,
i,
index,
monitor,

View File

@@ -20,6 +20,7 @@ import {
} from 'lib/types/options';
import { MatugenScheme, MatugenTheme, MatugenVariations } from 'lib/types/options';
import { UnitType } from 'lib/types/weather';
import { WorkspaceIcons, WorkspaceIconsColored } from 'lib/types/workspace';
// WARN: CHANGING THESE VALUES WILL PREVENT MATUGEN COLOR GENERATION FOR THE CHANGED VALUE
export const colors = {
@@ -191,6 +192,7 @@ const options = mkOptions(OPTIONS, {
numbered_active_highlighted_text_color: opt(colors.mantle),
numbered_active_underline_color: opt(colors.pink),
spacing: opt('0.5em'),
fontSize: opt('1.2em'),
},
windowtitle: {
background: opt(colors.base2),
@@ -810,12 +812,14 @@ const options = mkOptions(OPTIONS, {
workspaces: {
show_icons: opt(false),
show_numbered: opt(false),
showWsIcons: opt(false),
numbered_active_indicator: opt<ActiveWsIndicator>('underline'),
icons: {
available: opt(''),
active: opt(''),
occupied: opt(''),
},
workspaceIconMap: opt<WorkspaceIcons | WorkspaceIconsColored>({}),
workspaces: opt(10),
spacing: opt(1),
monitorSpecific: opt(true),

View File

@@ -3,8 +3,8 @@
font-size: 0.2em;
min-width: 4em;
min-height: 4em;
border-radius: 1.9rem * .6;
transition: 300ms * .5;
border-radius: 1.9rem * 0.6;
transition: 300ms * 0.5;
background-color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-workspaces-available);
color: if($bar-buttons-monochrome, $bar-buttons-icon, $bar-buttons-workspaces-available);
@@ -27,7 +27,7 @@
min-width: 0em;
min-height: 0em;
border-radius: 0em;
transition: 300ms * .5;
transition: 300ms * 0.5;
font-size: 1em;
}
@@ -38,7 +38,7 @@
border-radius: 0em;
transition: 0ms;
padding: 0em 0.2em;
font-size: 1.2em;
font-size: $bar-buttons-workspaces-fontSize;
}
&.underline {
@@ -66,7 +66,8 @@
&:hover .can_underline {
border-top: 0.1em solid transparent;
border-bottom: 0.1em solid if($bar-buttons-monochrome, $bar-buttons-workspaces-hover, $bar-buttons-workspaces-hover);
border-bottom: 0.1em solid
if($bar-buttons-monochrome, $bar-buttons-workspaces-hover, $bar-buttons-workspaces-hover);
}
&:hover .can_highlight {

View File

@@ -136,6 +136,14 @@ export const BarSettings = (): Scrollable<Gtk.Widget, Gtk.Widget> => {
******************************
*/
Header('Workspaces'),
Option({
opt: options.theme.bar.buttons.workspaces.fontSize,
title: 'Indicator Size',
subtitle:
'Only applicable to numbered workspaces and mapped icons\n' +
'Adjust with caution as it may cause the bar to expand',
type: 'string',
}),
Option({
opt: options.bar.workspaces.show_icons,
title: 'Show Workspace Icons',
@@ -180,6 +188,16 @@ export const BarSettings = (): Scrollable<Gtk.Widget, Gtk.Widget> => {
subtitle: 'Only applicable if Workspace Numbers are enabled',
type: 'string',
}),
Option({
opt: options.bar.workspaces.showWsIcons,
title: 'Map Workspaces to Icons',
type: 'boolean',
}),
Option({
opt: options.bar.workspaces.workspaceIconMap,
title: 'Workspace Icon Mappings',
type: 'object',
}),
Option({
opt: options.bar.workspaces.spacing,
title: 'Spacing',

View File

@@ -1,6 +1,6 @@
import options from 'options';
const { show_numbered, show_icons } = options.bar.workspaces;
const { show_numbered, show_icons, showWsIcons } = options.bar.workspaces;
const { monochrome: monoBar } = options.theme.bar.buttons;
const { monochrome: monoMenu } = options.theme.bar.menus;
const { matugen } = options.theme;
@@ -8,12 +8,21 @@ const { matugen } = options.theme;
show_numbered.connect('changed', ({ value }) => {
if (value === true) {
show_icons.value = false;
showWsIcons.value = false;
}
});
show_icons.connect('changed', ({ value }) => {
if (value === true) {
show_numbered.value = false;
showWsIcons.value = false;
}
});
showWsIcons.connect('changed', ({ value }) => {
if (value === true) {
show_numbered.value = false;
show_icons.value = false;
}
});