diff options
| author | Ryan Schanzenbacher <ryan@rschanz.org> | 2026-07-09 22:15:53 -0400 |
|---|---|---|
| committer | Ryan Schanzenbacher <ryan@rschanz.org> | 2026-07-09 22:15:53 -0400 |
| commit | d06784958d73159b5e4abafe5114804662114ed7 (patch) | |
| tree | d8464262c1aa1f10553a5b11a9fda3e505e71f7f /users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace | |
| parent | 1a71e94eb8ca1585201263cf654611ef6849d359 (diff) | |
move ubersicht modules in tree
Diffstat (limited to 'users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace')
5 files changed, 355 insertions, 0 deletions
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/opened-apps.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/opened-apps.jsx new file mode 100755 index 0000000..5b56966 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/opened-apps.jsx | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | import * as Uebersicht from "uebersicht"; | ||
| 2 | import * as AppIcons from "../../app-icons.js"; | ||
| 3 | import { SuspenseIcon } from "../icons/icon.jsx"; | ||
| 4 | import * as Utils from "../../utils.js"; | ||
| 5 | |||
| 6 | const { React } = Uebersicht; | ||
| 7 | |||
| 8 | /** | ||
| 9 | * OpenedApps component to display icons of opened applications. | ||
| 10 | * @param {Object} props - The component props. | ||
| 11 | * @param {Array} props.apps - The list of opened applications. | ||
| 12 | * @returns {JSX.Element|null} The rendered component or null if no apps are opened. | ||
| 13 | */ | ||
| 14 | export default function OpenedApps({ apps }) { | ||
| 15 | if (!apps.length) return null; | ||
| 16 | |||
| 17 | return apps.map((app, i) => { | ||
| 18 | const { focused } = app; | ||
| 19 | const appName = Utils.normalizeAppName(app["app-name"]); | ||
| 20 | const Icon = AppIcons.apps[appName] || AppIcons.apps.Default; | ||
| 21 | |||
| 22 | // Generate class names for the app icon | ||
| 23 | const classes = Utils.classNames("space__icon", { | ||
| 24 | "space__icon--focused": focused, | ||
| 25 | }); | ||
| 26 | |||
| 27 | return ( | ||
| 28 | <SuspenseIcon key={i}> | ||
| 29 | <Icon className={classes} /> | ||
| 30 | </SuspenseIcon> | ||
| 31 | ); | ||
| 32 | }); | ||
| 33 | } | ||
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/process.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/process.jsx new file mode 100755 index 0000000..0c461cc --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/process.jsx | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | import * as Uebersicht from "uebersicht"; | ||
| 2 | import Window from "./window.jsx"; | ||
| 3 | import * as Utils from "../../utils"; | ||
| 4 | import { useAerospaceContext } from "../aerospace-context.jsx"; | ||
| 5 | import { useSimpleBarContext } from "../simple-bar-context.jsx"; | ||
| 6 | |||
| 7 | export { processStyles as styles } from "../../styles/components/process"; | ||
| 8 | |||
| 9 | const { React } = Uebersicht; | ||
| 10 | |||
| 11 | /** | ||
| 12 | * Process component to display windows in the current space. | ||
| 13 | * @returns {JSX.Element|null} The rendered component or null if not visible. | ||
| 14 | */ | ||
| 15 | const Component = React.memo(() => { | ||
| 16 | // Get spaces from aerospace context | ||
| 17 | const { spaces } = useAerospaceContext(); | ||
| 18 | // Get settings and display index from simple bar context | ||
| 19 | const { settings, displayIndex } = useSimpleBarContext(); | ||
| 20 | const { spacesDisplay, process, widgets } = settings; | ||
| 21 | const { exclusionsAsRegex } = spacesDisplay; | ||
| 22 | const { processWidget } = widgets; | ||
| 23 | const { centered, showOnDisplay } = process; | ||
| 24 | |||
| 25 | // Determine if the component should be visible | ||
| 26 | const visible = | ||
| 27 | spaces?.length && | ||
| 28 | processWidget && | ||
| 29 | Utils.isVisibleOnDisplay(displayIndex, showOnDisplay); | ||
| 30 | |||
| 31 | if (!visible) return null; | ||
| 32 | |||
| 33 | // Find the focused space on the current display | ||
| 34 | const { windows = [] } = | ||
| 35 | spaces.find((space) => space.focused && space.monitor === displayIndex) || | ||
| 36 | {}; | ||
| 37 | |||
| 38 | if (!windows.length) return null; | ||
| 39 | |||
| 40 | // Get exclusions for filtering windows | ||
| 41 | const exclusions = exclusionsAsRegex | ||
| 42 | ? spacesDisplay.exclusions | ||
| 43 | : spacesDisplay.exclusions.split(", "); | ||
| 44 | |||
| 45 | const titleExclusions = exclusionsAsRegex | ||
| 46 | ? spacesDisplay.titleExclusions | ||
| 47 | : spacesDisplay.titleExclusions.split(", "); | ||
| 48 | |||
| 49 | // Generate class names for the component | ||
| 50 | const classes = Utils.classNames("process", { | ||
| 51 | "process--centered": centered, | ||
| 52 | }); | ||
| 53 | |||
| 54 | // Filter windows based on exclusions | ||
| 55 | const filteredWindows = windows.filter((window) => | ||
| 56 | Utils.filterApps(window, exclusions, titleExclusions, exclusionsAsRegex), | ||
| 57 | ); | ||
| 58 | |||
| 59 | return ( | ||
| 60 | <div className={classes}> | ||
| 61 | <div className="process__container"> | ||
| 62 | {filteredWindows.map((window, i) => ( | ||
| 63 | <Window key={i} window={window} /> | ||
| 64 | ))} | ||
| 65 | </div> | ||
| 66 | </div> | ||
| 67 | ); | ||
| 68 | }); | ||
| 69 | |||
| 70 | Component.displayName = "Process"; | ||
| 71 | |||
| 72 | export default Component; | ||
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/space.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/space.jsx new file mode 100755 index 0000000..ab91bbb --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/space.jsx | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | import * as Uebersicht from "uebersicht"; | ||
| 2 | import OpenedApps from "./opened-apps.jsx"; | ||
| 3 | import { useSimpleBarContext } from "../simple-bar-context.jsx"; | ||
| 4 | import * as Utils from "../../utils.js"; | ||
| 5 | import * as Aerospace from "../../aerospace.js"; | ||
| 6 | |||
| 7 | const { React } = Uebersicht; | ||
| 8 | |||
| 9 | /** | ||
| 10 | * Space component to display a single space. | ||
| 11 | * @param {Object} props - The component props. | ||
| 12 | * @param {Object} props.space - The space object. | ||
| 13 | * @param {boolean} props.lastOfSpace - Indicates if this is the last space of the monitor. | ||
| 14 | * @returns {JSX.Element|null} The rendered component. | ||
| 15 | */ | ||
| 16 | export default function Space({ space, lastOfSpace }) { | ||
| 17 | const { windows } = space; | ||
| 18 | const { settings } = useSimpleBarContext(); | ||
| 19 | const { spacesDisplay } = settings; | ||
| 20 | const { | ||
| 21 | displayAllSpacesOnAllScreens, | ||
| 22 | exclusionsAsRegex, | ||
| 23 | hideDuplicateAppsInSpaces, | ||
| 24 | } = spacesDisplay; | ||
| 25 | const { workspace, focused } = space; | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Handle click event to switch to the clicked space. | ||
| 29 | * @param {Event} e - The click event. | ||
| 30 | */ | ||
| 31 | const onClick = (e) => { | ||
| 32 | if (focused) return; | ||
| 33 | Aerospace.goToSpace(workspace); | ||
| 34 | Utils.clickEffect(e); | ||
| 35 | }; | ||
| 36 | |||
| 37 | // Determine if the space should be hidden | ||
| 38 | const hidden = !focused && !windows.length && spacesDisplay.hideEmptySpaces; | ||
| 39 | |||
| 40 | if (hidden) return null; | ||
| 41 | |||
| 42 | // Get exclusions and title exclusions based on settings | ||
| 43 | const exclusions = exclusionsAsRegex | ||
| 44 | ? spacesDisplay.exclusions | ||
| 45 | : spacesDisplay.exclusions.split(", "); | ||
| 46 | const titleExclusions = exclusionsAsRegex | ||
| 47 | ? spacesDisplay.titleExclusions | ||
| 48 | : spacesDisplay.titleExclusions.split(", "); | ||
| 49 | |||
| 50 | // Filter windows based on exclusions | ||
| 51 | const filteredWindows = windows.filter((window) => | ||
| 52 | Utils.filterApps(window, exclusions, titleExclusions, exclusionsAsRegex), | ||
| 53 | ); | ||
| 54 | |||
| 55 | // Remove duplicate apps if the setting is enabled | ||
| 56 | const displayedWindows = hideDuplicateAppsInSpaces | ||
| 57 | ? filteredWindows.reduce((acc, window) => { | ||
| 58 | const isDuplicate = acc.find( | ||
| 59 | (w) => w["app-name"] === window["app-name"], | ||
| 60 | ); | ||
| 61 | return isDuplicate ? acc : [...acc, window]; | ||
| 62 | }, []) | ||
| 63 | : filteredWindows; | ||
| 64 | |||
| 65 | // Determine the CSS classes for the space | ||
| 66 | const classes = Utils.classNames("space", { | ||
| 67 | "space--focused": focused, | ||
| 68 | "space--empty": windows.length, | ||
| 69 | }); | ||
| 70 | |||
| 71 | return ( | ||
| 72 | <React.Fragment> | ||
| 73 | {displayAllSpacesOnAllScreens && lastOfSpace && ( | ||
| 74 | <div className="spaces__separator" /> | ||
| 75 | )} | ||
| 76 | <div className={classes}> | ||
| 77 | <button className="space__inner" onClick={onClick}> | ||
| 78 | {workspace} | ||
| 79 | <OpenedApps apps={displayedWindows} /> | ||
| 80 | </button> | ||
| 81 | </div> | ||
| 82 | </React.Fragment> | ||
| 83 | ); | ||
| 84 | } | ||
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/spaces.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/spaces.jsx new file mode 100755 index 0000000..d576389 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/spaces.jsx | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | import * as Uebersicht from "uebersicht"; | ||
| 2 | import Space from "./space.jsx"; | ||
| 3 | import { useAerospaceContext } from "../aerospace-context.jsx"; | ||
| 4 | import { useSimpleBarContext } from "../simple-bar-context.jsx"; | ||
| 5 | import * as Utils from "../../utils.js"; | ||
| 6 | import * as AeroSpace from "../../aerospace.js"; | ||
| 7 | |||
| 8 | export { spacesStyles as styles } from "../../styles/components/spaces/spaces.js"; | ||
| 9 | |||
| 10 | const { React } = Uebersicht; | ||
| 11 | |||
| 12 | /** | ||
| 13 | * Spaces component to display spaces on the screen. | ||
| 14 | * @returns {JSX.Element|null} The rendered component. | ||
| 15 | */ | ||
| 16 | const Component = React.memo(() => { | ||
| 17 | // Get spaces from aerospace context | ||
| 18 | const { spaces } = useAerospaceContext(); | ||
| 19 | // Get displays, displayIndex, and settings from simple bar context | ||
| 20 | const { displays, displayIndex, settings } = useSimpleBarContext(); | ||
| 21 | const { spacesDisplay, process } = settings; | ||
| 22 | const { displayAllSpacesOnAllScreens, showOnDisplay } = spacesDisplay; | ||
| 23 | // Determine if the component should be visible on the current display | ||
| 24 | const visible = Utils.isVisibleOnDisplay(displayIndex, showOnDisplay); | ||
| 25 | const isProcessVisible = Utils.isVisibleOnDisplay( | ||
| 26 | displayIndex, | ||
| 27 | process.showOnDisplay | ||
| 28 | ); | ||
| 29 | |||
| 30 | // If not visible, return null | ||
| 31 | if (!visible) return null; | ||
| 32 | |||
| 33 | // If there are no spaces, return an empty div | ||
| 34 | if (!spaces?.length) { | ||
| 35 | return <div className="spaces spaces--empty" />; | ||
| 36 | } | ||
| 37 | |||
| 38 | // Map through displays and render spaces for the current display | ||
| 39 | return displays.map((display) => { | ||
| 40 | const displayId = AeroSpace.getDisplayIndex(display); | ||
| 41 | if (displayId !== displayIndex) return null; | ||
| 42 | |||
| 43 | // Filter spaces based on display settings | ||
| 44 | const filteredSpaces = displayAllSpacesOnAllScreens | ||
| 45 | ? spaces | ||
| 46 | : spaces.filter((space) => space.monitor === displayId); | ||
| 47 | |||
| 48 | return ( | ||
| 49 | <div key={displayId} className="spaces"> | ||
| 50 | {filteredSpaces.map((space, i) => { | ||
| 51 | const { workspace } = space; | ||
| 52 | const lastOfSpace = | ||
| 53 | i !== 0 && space.monitor !== spaces[i - 1].monitor; | ||
| 54 | |||
| 55 | return ( | ||
| 56 | <Space key={workspace} space={space} lastOfSpace={lastOfSpace} /> | ||
| 57 | ); | ||
| 58 | })} | ||
| 59 | {isProcessVisible && <div className="spaces__end-separator" />} | ||
| 60 | </div> | ||
| 61 | ); | ||
| 62 | }); | ||
| 63 | }); | ||
| 64 | |||
| 65 | Component.displayName = "Spaces"; | ||
| 66 | |||
| 67 | export default Component; | ||
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/window.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/window.jsx new file mode 100755 index 0000000..04b54d6 --- /dev/null +++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/aerospace/window.jsx | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | import * as Uebersicht from "uebersicht"; | ||
| 2 | import * as AppIcons from "../../app-icons"; | ||
| 3 | import { SuspenseIcon } from "../icons/icon.jsx"; | ||
| 4 | import { useSimpleBarContext } from "../simple-bar-context.jsx"; | ||
| 5 | import * as Utils from "../../utils"; | ||
| 6 | import * as Aerospace from "../../aerospace"; | ||
| 7 | |||
| 8 | const { React } = Uebersicht; | ||
| 9 | |||
| 10 | /** | ||
| 11 | * Window component to display a window in the process bar. | ||
| 12 | * @param {Object} props - The component props. | ||
| 13 | * @param {Object} props.window - The window object. | ||
| 14 | * @returns {JSX.Element|null} The rendered component. | ||
| 15 | */ | ||
| 16 | export default function Window({ window }) { | ||
| 17 | // Get settings from context | ||
| 18 | const { settings } = useSimpleBarContext(); | ||
| 19 | // Create a ref for the button element | ||
| 20 | const ref = React.useRef(); | ||
| 21 | // Destructure settings | ||
| 22 | const { | ||
| 23 | displayOnlyCurrent, | ||
| 24 | hideWindowTitle, | ||
| 25 | displayOnlyIcon, | ||
| 26 | expandAllProcesses, | ||
| 27 | } = settings.process; | ||
| 28 | // Destructure window properties | ||
| 29 | const { | ||
| 30 | focused, | ||
| 31 | "app-name": appName, | ||
| 32 | "window-title": title, | ||
| 33 | "window-id": id, | ||
| 34 | } = window; | ||
| 35 | |||
| 36 | // If displayOnlyCurrent is true and the window is not focused, return null | ||
| 37 | if (displayOnlyCurrent && !focused) { | ||
| 38 | return null; | ||
| 39 | } | ||
| 40 | |||
| 41 | // Get the icon for the app or use the default icon | ||
| 42 | const Icon = AppIcons.apps[appName] || AppIcons.apps.Default; | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Handle click event on the window button. | ||
| 46 | * @param {Event} e - The click event. | ||
| 47 | */ | ||
| 48 | const onClick = (e) => { | ||
| 49 | !displayOnlyCurrent && Utils.clickEffect(e); | ||
| 50 | Aerospace.focusWindow(id); | ||
| 51 | }; | ||
| 52 | |||
| 53 | /** | ||
| 54 | * Handle mouse enter event on the window button. | ||
| 55 | */ | ||
| 56 | const onMouseEnter = () => { | ||
| 57 | Utils.startSliding(ref.current, ".process__inner", ".process__name"); | ||
| 58 | }; | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Handle mouse leave event on the window button. | ||
| 62 | */ | ||
| 63 | const onMouseLeave = () => { | ||
| 64 | Utils.stopSliding(ref.current, ".process__name"); | ||
| 65 | }; | ||
| 66 | |||
| 67 | // Generate class names based on settings and window state | ||
| 68 | const classes = Utils.classNames("process__window", { | ||
| 69 | "process__window--expanded": expandAllProcesses, | ||
| 70 | "process__window--focused": !displayOnlyCurrent && focused, | ||
| 71 | "process__window--only-current": displayOnlyCurrent, | ||
| 72 | "process__window--only-icon": displayOnlyIcon, | ||
| 73 | }); | ||
| 74 | |||
| 75 | // Clean up the window title | ||
| 76 | const cleanedUpName = | ||
| 77 | appName !== title && title.length ? `${appName} / ${title}` : appName; | ||
| 78 | const processName = hideWindowTitle ? appName : cleanedUpName; | ||
| 79 | |||
| 80 | // Render the window button | ||
| 81 | return ( | ||
| 82 | <button | ||
| 83 | ref={ref} | ||
| 84 | className={classes} | ||
| 85 | onClick={onClick} | ||
| 86 | onMouseEnter={displayOnlyIcon ? undefined : onMouseEnter} | ||
| 87 | onMouseLeave={displayOnlyIcon ? undefined : onMouseLeave} | ||
| 88 | > | ||
| 89 | <SuspenseIcon> | ||
| 90 | <Icon className="process__icon" /> | ||
| 91 | </SuspenseIcon> | ||
| 92 | {!displayOnlyIcon && ( | ||
| 93 | <span className="process__inner"> | ||
| 94 | <span className="process__name">{processName}</span> | ||
| 95 | </span> | ||
| 96 | )} | ||
| 97 | </button> | ||
| 98 | ); | ||
| 99 | } | ||
