users/ryan/modules/simple-bar/simple-bar-source/index.jsx
2e30121671a730a2b4bc2f82d2e30ed5c9ff70e5
· 9.7 KB · 267 lines
raw
| 1 | import * as Uebersicht from "uebersicht"; |
| 2 | import * as Error from "./lib/components/error.jsx"; |
| 3 | import SimpleBarContextProvider from "./lib/components/simple-bar-context.jsx"; |
| 4 | import UserWidgets from "./lib/components/data/user-widgets.jsx"; |
| 5 | // Each simple-bar widgets exports both a "Component" or "Widget" render function |
| 6 | // and a "styles" string containing its own CSS |
| 7 | import * as Variables from "./lib/styles/core/variables"; |
| 8 | import * as Base from "./lib/styles/core/base"; |
| 9 | import * as Spaces from "./lib/styles/components/spaces/spaces"; |
| 10 | import * as Process from "./lib/styles/components/process"; |
| 11 | import * as Zoom from "./lib/components/data/zoom.jsx"; |
| 12 | import * as Time from "./lib/components/data/time.jsx"; |
| 13 | import * as DateDisplay from "./lib/components/data/date-display.jsx"; |
| 14 | import * as GitHub from "./lib/components/data/github.jsx"; |
| 15 | import * as Weather from "./lib/components/data/weather.jsx"; |
| 16 | import * as Netstats from "./lib/components/data/netstats.jsx"; |
| 17 | import * as Cpu from "./lib/components/data/cpu.jsx"; |
| 18 | import * as Gpu from "./lib/components/data/gpu.jsx"; |
| 19 | import * as Memory from "./lib/components/data/memory.jsx"; |
| 20 | import * as Battery from "./lib/components/data/battery.jsx"; |
| 21 | import * as Sound from "./lib/components/data/sound.jsx"; |
| 22 | import * as Mic from "./lib/components/data/mic.jsx"; |
| 23 | import * as Wifi from "./lib/components/data/wifi.jsx"; |
| 24 | import * as ViscosityVPN from "./lib/components/data/viscosity-vpn.jsx"; |
| 25 | import * as Keyboard from "./lib/components/data/keyboard.jsx"; |
| 26 | import * as Spotify from "./lib/components/data/spotify.jsx"; |
| 27 | import * as YouTubeMusic from "./lib/components/data/youtube-music.jsx"; |
| 28 | import * as Crypto from "./lib/components/data/crypto.jsx"; |
| 29 | import * as Stock from "./lib/components/data/stock.jsx"; |
| 30 | import * as Music from "./lib/components/data/music.jsx"; |
| 31 | import * as Mpd from "./lib/components/data/mpd.jsx"; |
| 32 | import * as BrowserTrack from "./lib/components/data/browser-track.jsx"; |
| 33 | import * as Notifications from "./lib/components/data/notifications.jsx"; |
| 34 | import * as NextMeeting from "./lib/components/data/next-meeting.jsx"; |
| 35 | import * as Specter from "./lib/components/data/specter.jsx"; |
| 36 | import * as Graph from "./lib/components/data/graph.jsx"; |
| 37 | import * as DataWidgetLoader from "./lib/components/data/data-widget-loader.jsx"; |
| 38 | import * as DataWidget from "./lib/components/data/data-widget.jsx"; |
| 39 | import * as SideIcon from "./lib/components/side-icon.jsx"; |
| 40 | import * as Missives from "./lib/components/missives/missives.jsx"; |
| 41 | import * as Utils from "./lib/utils"; |
| 42 | import * as Settings from "./lib/settings"; |
| 43 | |
| 44 | // Destructure React from Uebersicht in order to make eslint catch hook rules for example |
| 45 | const { React } = Uebersicht; |
| 46 | |
| 47 | // Spaces & process components are lazy loaded to avoid loading them when not needed |
| 48 | const YabaiContextProvider = React.lazy( |
| 49 | () => import("./lib/components/yabai-context.jsx"), |
| 50 | ); |
| 51 | const AerospaceContextProvider = React.lazy( |
| 52 | () => import("./lib/components/aerospace-context.jsx"), |
| 53 | ); |
| 54 | const YabaiSpaces = React.lazy( |
| 55 | () => import("./lib/components/yabai/spaces.jsx"), |
| 56 | ); |
| 57 | const YabaiProcess = React.lazy( |
| 58 | () => import("./lib/components/yabai/process.jsx"), |
| 59 | ); |
| 60 | const AerospaceSpaces = React.lazy( |
| 61 | () => import("./lib/components/aerospace/spaces.jsx"), |
| 62 | ); |
| 63 | const AerospaceProcess = React.lazy( |
| 64 | () => import("./lib/components/aerospace/process.jsx"), |
| 65 | ); |
| 66 | |
| 67 | // Set refresh frequency to false |
| 68 | // Übersicht auto-refresh system is not required as simple-bar works in sync with |
| 69 | // yabai or AeroSpaces for spaces & process widgets and data widgets are refreshed with |
| 70 | // their local refresh functions |
| 71 | const refreshFrequency = false; |
| 72 | |
| 73 | // Init settings from file if existing |
| 74 | Settings.init(); |
| 75 | |
| 76 | // Get settings from the Settings module |
| 77 | const settings = Settings.get(); |
| 78 | const { |
| 79 | // Do not edit the yabaiPath or aerospacePath lines, theses values are simply |
| 80 | // a default value used if nothing is defined in settings. |
| 81 | // You can setup your custom yabai or AeroSpace path in the settings module (Global tab) : |
| 82 | // while on an empty workspace, click on simple-bar then press cmd + , to open it. |
| 83 | yabaiPath = "/opt/homebrew/bin/yabai", |
| 84 | aerospacePath = "/opt/homebrew/bin/aerospace", |
| 85 | windowManager, // Window manager type (yabai or aerospace) |
| 86 | shell, // Shell to use for commands |
| 87 | enableServer, // Enable server mode |
| 88 | yabaiServerRefresh, // Refresh rate for yabai server |
| 89 | } = settings.global; |
| 90 | const { hideWindowTitle, displayOnlyIcon, displaySkhdMode } = settings.process; |
| 91 | |
| 92 | // Determine if signals should be disabled based on settings |
| 93 | const disableSignals = enableServer && yabaiServerRefresh; |
| 94 | const enableTitleChangedSignal = !hideWindowTitle && !displayOnlyIcon; |
| 95 | |
| 96 | // Construct command arguments based on window manager type |
| 97 | const yabaiArgs = `${yabaiPath} ${displaySkhdMode} ${disableSignals} ${enableTitleChangedSignal}`; |
| 98 | const aerospaceArgs = `${aerospacePath}`; |
| 99 | const args = getArguments(windowManager, yabaiArgs, aerospaceArgs); |
| 100 | const command = `${shell} simple-bar/lib/scripts/init-${windowManager}.sh ${args}`; |
| 101 | |
| 102 | // Inject global styles into the document |
| 103 | // I prefer using native CSS instead of Emotion bundled by default in Übersicht |
| 104 | Utils.injectStyles("simple-bar-index-styles", [ |
| 105 | Variables.styles, |
| 106 | Base.styles, |
| 107 | Spaces.styles, |
| 108 | Process.styles, |
| 109 | Settings.styles, |
| 110 | DataWidget.styles, |
| 111 | DateDisplay.styles, |
| 112 | Zoom.styles, |
| 113 | Time.styles, |
| 114 | GitHub.styles, |
| 115 | Weather.styles, |
| 116 | Netstats.styles, |
| 117 | Cpu.styles, |
| 118 | Gpu.styles, |
| 119 | Memory.styles, |
| 120 | Crypto.styles, |
| 121 | Stock.styles, |
| 122 | Battery.styles, |
| 123 | Wifi.styles, |
| 124 | ViscosityVPN.styles, |
| 125 | Keyboard.styles, |
| 126 | Mic.styles, |
| 127 | Sound.styles, |
| 128 | Spotify.styles, |
| 129 | YouTubeMusic.styles, |
| 130 | Music.styles, |
| 131 | Mpd.styles, |
| 132 | BrowserTrack.styles, |
| 133 | Notifications.styles, |
| 134 | NextMeeting.styles, |
| 135 | Specter.styles, |
| 136 | Graph.styles, |
| 137 | DataWidgetLoader.styles, |
| 138 | settings.customStyles.styles, |
| 139 | SideIcon.styles, |
| 140 | Missives.styles, |
| 141 | ]); |
| 142 | |
| 143 | // Render function to display the bar |
| 144 | function render({ output, error }) { |
| 145 | // Define base classes for the bar based on settings |
| 146 | const baseClasses = Utils.classNames("simple-bar", { |
| 147 | "simple-bar--floating": settings.global.floatingBar, |
| 148 | "simple-bar--no-bar-background": settings.global.noBarBg, |
| 149 | "simple-bar--no-color-in-data": settings.global.noColorInData, |
| 150 | "simple-bar--on-bottom": settings.global.bottomBar, |
| 151 | "simple-bar--inline-spaces-options": settings.global.inlineSpacesOptions, |
| 152 | "simple-bar--animations-disabled": settings.global.disableAnimations, |
| 153 | "simple-bar--spaces-background-color-as-foreground": |
| 154 | settings.global.spacesBackgroundColorAsForeground, |
| 155 | "simple-bar--widgets-background-color-as-foreground": |
| 156 | settings.global.widgetsBackgroundColorAsForeground, |
| 157 | "simple-bar--process-aligned-to-left": !settings.global.centered, |
| 158 | }); |
| 159 | |
| 160 | // Handle errors |
| 161 | if (error) { |
| 162 | // eslint-disable-next-line no-console |
| 163 | console.error("Error in index.jsx", error); |
| 164 | return <Error.Component type="error" classes={baseClasses} />; |
| 165 | } |
| 166 | if (!output) { |
| 167 | return <Error.Component type="noOutput" classes={baseClasses} />; |
| 168 | } |
| 169 | |
| 170 | // Cleanup the output data |
| 171 | const cleanedUpOutput = Utils.cleanupOutput(output); |
| 172 | |
| 173 | // Handle specific errors related to yabai or AeroSpace |
| 174 | const errors = ["yabaiError", "aerospaceError"]; |
| 175 | if (errors.includes(cleanedUpOutput)) { |
| 176 | return <Error.Component type={cleanedUpOutput} classes={baseClasses} />; |
| 177 | } |
| 178 | |
| 179 | // Parse the output data |
| 180 | const data = Utils.parseJson(cleanedUpOutput); |
| 181 | if (!data) return <Error.Component type="noData" classes={baseClasses} />; |
| 182 | |
| 183 | const { displays, shadow, skhdMode, SIP, spaces, windows } = data; |
| 184 | |
| 185 | // Check if SIP (System Integrity Protection) is disabled |
| 186 | const SIPDisabled = SIP !== "System Integrity Protection status: enabled."; |
| 187 | |
| 188 | // Define additional classes based on data |
| 189 | const classes = Utils.classNames(baseClasses, { |
| 190 | "simple-bar--no-shadow": shadow !== "on", |
| 191 | }); |
| 192 | |
| 193 | // Handle bar focus ring on click |
| 194 | Utils.handleBarFocus(); |
| 195 | |
| 196 | // Render the bar with appropriate components and data |
| 197 | return ( |
| 198 | <SimpleBarContextProvider |
| 199 | initialSettings={settings} |
| 200 | displays={displays} |
| 201 | SIPDisabled={SIPDisabled} |
| 202 | > |
| 203 | <div className={classes}> |
| 204 | <SideIcon.Component /> |
| 205 | <React.Suspense fallback={<React.Fragment />}> |
| 206 | {windowManager === "yabai" && ( |
| 207 | <YabaiContextProvider |
| 208 | spaces={spaces} |
| 209 | windows={windows} |
| 210 | skhdMode={skhdMode} |
| 211 | > |
| 212 | <YabaiSpaces /> |
| 213 | <YabaiProcess /> |
| 214 | </YabaiContextProvider> |
| 215 | )} |
| 216 | {windowManager === "aerospace" && ( |
| 217 | <AerospaceContextProvider> |
| 218 | <AerospaceSpaces /> |
| 219 | <AerospaceProcess /> |
| 220 | </AerospaceContextProvider> |
| 221 | )} |
| 222 | </React.Suspense> |
| 223 | <Settings.Wrapper /> |
| 224 | <div className="simple-bar__data"> |
| 225 | <UserWidgets /> |
| 226 | <Zoom.Widget /> |
| 227 | <BrowserTrack.Widget /> |
| 228 | <Spotify.Widget /> |
| 229 | <YouTubeMusic.Widget /> |
| 230 | <Crypto.Widget /> |
| 231 | <Stock.Widget /> |
| 232 | <Music.Widget /> |
| 233 | <Mpd.Widget /> |
| 234 | <GitHub.Widget /> |
| 235 | <Weather.Widget /> |
| 236 | <Netstats.Widget /> |
| 237 | <Cpu.Widget /> |
| 238 | <Gpu.Widget /> |
| 239 | <Memory.Widget /> |
| 240 | <Battery.Widget /> |
| 241 | <Notifications.Widget /> |
| 242 | <NextMeeting.Widget /> |
| 243 | <Mic.Widget /> |
| 244 | <Sound.Widget /> |
| 245 | <ViscosityVPN.Widget /> |
| 246 | <Wifi.Widget /> |
| 247 | <Keyboard.Widget /> |
| 248 | <DateDisplay.Widget /> |
| 249 | <Time.Widget /> |
| 250 | </div> |
| 251 | <Missives.Component /> |
| 252 | </div> |
| 253 | </SimpleBarContextProvider> |
| 254 | ); |
| 255 | } |
| 256 | |
| 257 | export { command, refreshFrequency, render }; |
| 258 | |
| 259 | function getArguments(windowManager, yabaiArgs, aerospaceArgs) { |
| 260 | if (windowManager === "yabai") { |
| 261 | return yabaiArgs; |
| 262 | } |
| 263 | if (windowManager === "aerospace") { |
| 264 | return aerospaceArgs; |
| 265 | } |
| 266 | return ""; |
| 267 | } |