Initial commit
This commit is contained in:
6
app.ts
6
app.ts
@@ -6,7 +6,7 @@ import { runCLI } from 'src/services/cli/commander';
|
|||||||
import { InitializationService } from 'src/core/initialization';
|
import { InitializationService } from 'src/core/initialization';
|
||||||
|
|
||||||
App.start({
|
App.start({
|
||||||
instanceName: 'hyprpanel',
|
instanceName: 'hyprpanel-levl',
|
||||||
requestHandler: (request: string, res: (response: unknown) => void) => runCLI(request, res),
|
requestHandler: (request: string, res: (response: unknown) => void) => runCLI(request, res),
|
||||||
main: () => InitializationService.initialize(),
|
main: () => InitializationService.initialize(),
|
||||||
});
|
});
|
||||||
|
|||||||
8484
package-lock.json
generated
8484
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
58
package.json
58
package.json
@@ -1,31 +1,31 @@
|
|||||||
{
|
{
|
||||||
"name": "hyprpanel",
|
"name": "hyprpanel",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "A customizable panel built for Hyprland.",
|
"description": "A customizable panel built for Hyprland.",
|
||||||
"main": "app.ts",
|
"main": "app.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint --config .eslintrc.json .",
|
"lint": "eslint --config .eslintrc.json .",
|
||||||
"lint:fix": "eslint --config .eslintrc.json . --fix",
|
"lint:fix": "eslint --config .eslintrc.json . --fix",
|
||||||
"format": "prettier --write 'modules/**/*.ts'",
|
"format": "prettier --write 'modules/**/*.ts'",
|
||||||
"knip": "knip"
|
"knip": "knip"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astal": "/usr/share/astal/gjs"
|
"astal": "/usr/share/astal/gjs"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.15.17",
|
"@types/node": "^22.15.17",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.5.0",
|
"@typescript-eslint/eslint-plugin": "^8.5.0",
|
||||||
"@typescript-eslint/parser": "^8.5.0",
|
"@typescript-eslint/parser": "^8.5.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-import": "^2.30.0",
|
"eslint-plugin-import": "^2.30.0",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"knip": "^5.55.1",
|
"knip": "^5.55.1",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"tsconfig-paths": "^4.2.0",
|
"tsconfig-paths": "^4.2.0",
|
||||||
"typescript": "5.7.3"
|
"typescript": "5.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { isValidGjsColor } from 'src/lib/validation/colors';
|
|||||||
import { AppIconOptions } from './types';
|
import { AppIconOptions } from './types';
|
||||||
import { WorkspaceIconMap } from '../types';
|
import { WorkspaceIconMap } from '../types';
|
||||||
import { unique } from 'src/lib/array/helpers';
|
import { unique } from 'src/lib/array/helpers';
|
||||||
|
import {Apps ,AstalAppsApplication} from "gi://AstalApps"
|
||||||
|
|
||||||
const hyprlandService = AstalHyprland.get_default();
|
const hyprlandService = AstalHyprland.get_default();
|
||||||
const { monochrome, background } = options.theme.bar.buttons;
|
const { monochrome, background } = options.theme.bar.buttons;
|
||||||
@@ -151,7 +152,13 @@ export const getAppIcon = (
|
|||||||
return iconEntry?.[1] ?? defaultIcon;
|
return iconEntry?.[1] ?? defaultIcon;
|
||||||
};
|
};
|
||||||
|
|
||||||
let icons = workspaceClients.reduce((iconAccumulator, [clientClass, clientTitle]) => {
|
|
||||||
|
|
||||||
|
let icons = getAppIconNew(hyprlandService
|
||||||
|
.get_clients()
|
||||||
|
.filter((client) => client?.workspace?.id === workspaceIndex))
|
||||||
|
|
||||||
|
icons = workspaceClients.reduce((iconAccumulator, [clientClass, clientTitle]) => {
|
||||||
const icon = findIconForClient(clientClass, clientTitle);
|
const icon = findIconForClient(clientClass, clientTitle);
|
||||||
|
|
||||||
if (icon !== undefined) {
|
if (icon !== undefined) {
|
||||||
@@ -161,6 +168,7 @@ export const getAppIcon = (
|
|||||||
return iconAccumulator;
|
return iconAccumulator;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
if (icons.length) {
|
if (icons.length) {
|
||||||
if (removeDuplicateIcons) {
|
if (removeDuplicateIcons) {
|
||||||
icons = unique(icons);
|
icons = unique(icons);
|
||||||
@@ -172,6 +180,35 @@ export const getAppIcon = (
|
|||||||
return defaultIcon;
|
return defaultIcon;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// todo implement caching to make it so much faster hopefully
|
||||||
|
export function getAppIconNew(
|
||||||
|
workspaceIndex: number,
|
||||||
|
apps: AstalAppsApplication
|
||||||
|
) : string[] {
|
||||||
|
const clients = hyprlandService
|
||||||
|
.get_clients()
|
||||||
|
.filter((client) => client?.workspace?.id === workspaceIndex);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let icons = clients?.map((client) =>
|
||||||
|
apps
|
||||||
|
.filter((app: AstalHyprland.app) =>
|
||||||
|
app.wm_class == client.get_class() ||
|
||||||
|
app.wm_class == client?.initial_title ||
|
||||||
|
app.wm_class == getWMClass(client) ||
|
||||||
|
app.name == client?.initial_title)
|
||||||
|
.map((app: AstalHyprland.app) => app.icon_name).at(0) ?? "missing-symbolic"
|
||||||
|
)
|
||||||
|
return icons.length > 0 ? icons : ["application-x-executable"]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWMClass(client: AstalHyprland.Client | undefined) {
|
||||||
|
return client.initial_class.split(".").reverse().at(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the class names for a workspace.
|
* Renders the class names for a workspace.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { initWorkspaceEvents } from './helpers/utils';
|
import { initWorkspaceEvents } from './helpers/utils';
|
||||||
import { getAppIcon, getWsColor, renderClassnames, renderLabel } from './helpers';
|
import { getAppIcon, getWsColor, renderClassnames, renderLabel, getAppIconNew } from './helpers';
|
||||||
import { bind, Variable } from 'astal';
|
import { bind, Variable } from 'astal';
|
||||||
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
|
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
|
||||||
import { Gtk } from 'astal/gtk3';
|
import { Gtk } from 'astal/gtk3';
|
||||||
@@ -7,6 +7,8 @@ import { WorkspaceService } from 'src/services/workspace';
|
|||||||
import options from 'src/configuration';
|
import options from 'src/configuration';
|
||||||
import { isPrimaryClick } from 'src/lib/events/mouse';
|
import { isPrimaryClick } from 'src/lib/events/mouse';
|
||||||
import { WorkspaceIconMap, ApplicationIcons } from './types';
|
import { WorkspaceIconMap, ApplicationIcons } from './types';
|
||||||
|
import Apps from "gi://AstalApps"
|
||||||
|
|
||||||
|
|
||||||
const workspaceService = WorkspaceService.getInstance();
|
const workspaceService = WorkspaceService.getInstance();
|
||||||
|
|
||||||
@@ -101,14 +103,10 @@ export const WorkspaceModule = ({ monitor }: WorkspaceModuleProps): JSX.Element
|
|||||||
monitorList,
|
monitorList,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const apps = new Apps.Apps({}).get_list()
|
||||||
|
|
||||||
return workspacesToRender.map((wsId, index) => {
|
return workspacesToRender.map((wsId, index) => {
|
||||||
const appIcons = displayApplicationIcons
|
const appIcons = getAppIconNew(wsId, apps);
|
||||||
? getAppIcon(wsId, appIconOncePerWorkspace, {
|
|
||||||
iconMap: applicationIconMapping,
|
|
||||||
defaultIcon: applicationIconFallback,
|
|
||||||
emptyIcon: applicationIconEmptyWorkspace,
|
|
||||||
})
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@@ -119,9 +117,8 @@ export const WorkspaceModule = ({ monitor }: WorkspaceModuleProps): JSX.Element
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<label
|
<box
|
||||||
valign={Gtk.Align.CENTER}
|
css={
|
||||||
css={
|
|
||||||
`margin: 0rem ${0.375 * spacingValue}rem;` +
|
`margin: 0rem ${0.375 * spacingValue}rem;` +
|
||||||
`${displayWorkspaceIcons && !matugenEnabled ? getWsColor(workspaceIconMapping, wsId, smartHighlightEnabled, monitor) : ''}`
|
`${displayWorkspaceIcons && !matugenEnabled ? getWsColor(workspaceIconMapping, wsId, smartHighlightEnabled, monitor) : ''}`
|
||||||
}
|
}
|
||||||
@@ -134,27 +131,21 @@ export const WorkspaceModule = ({ monitor }: WorkspaceModuleProps): JSX.Element
|
|||||||
monitor,
|
monitor,
|
||||||
wsId,
|
wsId,
|
||||||
)}
|
)}
|
||||||
label={renderLabel(
|
|
||||||
displayIcons,
|
|
||||||
availableStatus,
|
|
||||||
activeStatus,
|
|
||||||
occupiedStatus,
|
|
||||||
displayApplicationIcons,
|
|
||||||
appIcons,
|
|
||||||
workspaceMaskFlag,
|
|
||||||
displayWorkspaceIcons,
|
|
||||||
workspaceIconMapping,
|
|
||||||
wsId,
|
|
||||||
index,
|
|
||||||
monitor,
|
|
||||||
)}
|
|
||||||
setup={(self) => {
|
setup={(self) => {
|
||||||
const currentWsClients = clients.filter(
|
const currentWsClients = clients.filter(
|
||||||
(client) => client?.workspace?.id === wsId,
|
(client) => client?.workspace?.id === wsId,
|
||||||
);
|
);
|
||||||
self.toggleClassName('occupied', currentWsClients.length > 0);
|
self.toggleClassName('occupied', currentWsClients.length > 0);
|
||||||
}}
|
}}>
|
||||||
/>
|
|
||||||
|
{
|
||||||
|
appIcons?.map(icon =>
|
||||||
|
<icon
|
||||||
|
icon={icon || "image-missing"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</box>
|
||||||
|
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -57,7 +57,9 @@ export class WorkspaceService {
|
|||||||
let allPotentialWorkspaces = range(totalWorkspaces || 8);
|
let allPotentialWorkspaces = range(totalWorkspaces || 8);
|
||||||
const allWorkspaceInstances = workspaceInstances ?? [];
|
const allWorkspaceInstances = workspaceInstances ?? [];
|
||||||
|
|
||||||
const activeWorkspaceIds = allWorkspaceInstances.map((workspaceInstance) => workspaceInstance.id);
|
const activeWorkspaceIds = allWorkspaceInstances.filter(
|
||||||
|
(workspaceInstance) => !workspaceInstance.name.startsWith("special:")
|
||||||
|
).map((workspaceInstance) => workspaceInstance.id);
|
||||||
|
|
||||||
const monitorReferencesForActiveWorkspaces = allWorkspaceInstances.map((workspaceInstance) => {
|
const monitorReferencesForActiveWorkspaces = allWorkspaceInstances.map((workspaceInstance) => {
|
||||||
return {
|
return {
|
||||||
@@ -171,6 +173,9 @@ export class WorkspaceService {
|
|||||||
|
|
||||||
const workspaceMonitorReferences = allWorkspaceInstances
|
const workspaceMonitorReferences = allWorkspaceInstances
|
||||||
.filter((workspaceInstance) => workspaceInstance !== null)
|
.filter((workspaceInstance) => workspaceInstance !== null)
|
||||||
|
.filter(
|
||||||
|
(workspaceInstance) => !workspaceInstance.name.startsWith("special:")
|
||||||
|
)
|
||||||
.map((workspaceInstance) => {
|
.map((workspaceInstance) => {
|
||||||
return {
|
return {
|
||||||
id: workspaceInstance.monitor?.id,
|
id: workspaceInstance.monitor?.id,
|
||||||
@@ -224,6 +229,9 @@ export class WorkspaceService {
|
|||||||
.filter(
|
.filter(
|
||||||
(workspaceInstance) => hyprlandService.focusedMonitor.id === workspaceInstance.monitor?.id,
|
(workspaceInstance) => hyprlandService.focusedMonitor.id === workspaceInstance.monitor?.id,
|
||||||
)
|
)
|
||||||
|
.filter(
|
||||||
|
(workspaceInstance) => !workspaceInstance.name.startsWith("special:")
|
||||||
|
)
|
||||||
.map((workspaceInstance) => workspaceInstance.id);
|
.map((workspaceInstance) => workspaceInstance.id);
|
||||||
|
|
||||||
const assignedOrOccupiedWorkspaces = activeWorkspaceIds.sort((a, b) => a - b);
|
const assignedOrOccupiedWorkspaces = activeWorkspaceIds.sort((a, b) => a - b);
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
.workspaces {
|
.workspaces {
|
||||||
label {
|
label, box {
|
||||||
font-size: 0.2em;
|
font-size: 0.2em;
|
||||||
min-width: $bar-buttons-workspaces-pill-width;
|
min-width: $bar-buttons-workspaces-pill-width;
|
||||||
min-height: $bar-buttons-workspaces-pill-height;
|
min-height: $bar-buttons-workspaces-pill-height;
|
||||||
border-radius: $bar-buttons-workspaces-pill-radius;
|
border-radius: $bar-buttons-workspaces-pill-radius;
|
||||||
transition: 300ms * 0.5;
|
transition: 300ms * 0.5;
|
||||||
background-color: $bar-buttons-workspaces-available;
|
|
||||||
color: $bar-buttons-workspaces-available;
|
color: $bar-buttons-workspaces-available;
|
||||||
|
|
||||||
&.occupied {
|
&.occupied {
|
||||||
@@ -58,7 +57,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.workspace-button {
|
.workspace-button {
|
||||||
&:hover label {
|
&:hover label, box {
|
||||||
color: $bar-buttons-workspaces-hover;
|
color: $bar-buttons-workspaces-hover;
|
||||||
|
|
||||||
&.default {
|
&.default {
|
||||||
|
|||||||
Reference in New Issue
Block a user