aboutsummaryrefslogtreecommitdiff
path: root/users/ryan/modules/simple-bar/simple-bar-source/index.jsx
blob: bc817abb6755ad1ccc53a9f00b63625ad286781b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
import * as Uebersicht from "uebersicht";
import * as Error from "./lib/components/error.jsx";
import SimpleBarContextProvider from "./lib/components/simple-bar-context.jsx";
import UserWidgets from "./lib/components/data/user-widgets.jsx";
// Each simple-bar widgets exports both a "Component" or "Widget" render function
// and a "styles" string containing its own CSS
import * as Variables from "./lib/styles/core/variables";
import * as Base from "./lib/styles/core/base";
import * as Spaces from "./lib/styles/components/spaces/spaces";
import * as Process from "./lib/styles/components/process";
import * as Zoom from "./lib/components/data/zoom.jsx";
import * as Time from "./lib/components/data/time.jsx";
import * as DateDisplay from "./lib/components/data/date-display.jsx";
import * as GitHub from "./lib/components/data/github.jsx";
import * as Weather from "./lib/components/data/weather.jsx";
import * as Netstats from "./lib/components/data/netstats.jsx";
import * as Cpu from "./lib/components/data/cpu.jsx";
import * as Gpu from "./lib/components/data/gpu.jsx";
import * as Memory from "./lib/components/data/memory.jsx";
import * as Battery from "./lib/components/data/battery.jsx";
import * as Sound from "./lib/components/data/sound.jsx";
import * as Mic from "./lib/components/data/mic.jsx";
import * as Wifi from "./lib/components/data/wifi.jsx";
import * as ViscosityVPN from "./lib/components/data/viscosity-vpn.jsx";
import * as Keyboard from "./lib/components/data/keyboard.jsx";
import * as Spotify from "./lib/components/data/spotify.jsx";
import * as YouTubeMusic from "./lib/components/data/youtube-music.jsx";
import * as Crypto from "./lib/components/data/crypto.jsx";
import * as Stock from "./lib/components/data/stock.jsx";
import * as Music from "./lib/components/data/music.jsx";
import * as Mpd from "./lib/components/data/mpd.jsx";
import * as BrowserTrack from "./lib/components/data/browser-track.jsx";
import * as Notifications from "./lib/components/data/notifications.jsx";
import * as NextMeeting from "./lib/components/data/next-meeting.jsx";
import * as Specter from "./lib/components/data/specter.jsx";
import * as Graph from "./lib/components/data/graph.jsx";
import * as DataWidgetLoader from "./lib/components/data/data-widget-loader.jsx";
import * as DataWidget from "./lib/components/data/data-widget.jsx";
import * as SideIcon from "./lib/components/side-icon.jsx";
import * as Missives from "./lib/components/missives/missives.jsx";
import * as Utils from "./lib/utils";
import * as Settings from "./lib/settings";

// Destructure React from Uebersicht in order to make eslint catch hook rules for example
const { React } = Uebersicht;

// Spaces & process components are lazy loaded to avoid loading them when not needed
const YabaiContextProvider = React.lazy(
  () => import("./lib/components/yabai-context.jsx"),
);
const AerospaceContextProvider = React.lazy(
  () => import("./lib/components/aerospace-context.jsx"),
);
const YabaiSpaces = React.lazy(
  () => import("./lib/components/yabai/spaces.jsx"),
);
const YabaiProcess = React.lazy(
  () => import("./lib/components/yabai/process.jsx"),
);
const AerospaceSpaces = React.lazy(
  () => import("./lib/components/aerospace/spaces.jsx"),
);
const AerospaceProcess = React.lazy(
  () => import("./lib/components/aerospace/process.jsx"),
);

// Set refresh frequency to false
// Übersicht auto-refresh system is not required as simple-bar works in sync with
// yabai or AeroSpaces for spaces & process widgets and data widgets are refreshed with
// their local refresh functions
const refreshFrequency = false;

// Init settings from file if existing
Settings.init();

// Get settings from the Settings module
const settings = Settings.get();
const {
  // Do not edit the yabaiPath or aerospacePath lines, theses values are simply
  // a default value used if nothing is defined in settings.
  // You can setup your custom yabai or AeroSpace path in the settings module (Global tab) :
  // while on an empty workspace, click on simple-bar then press cmd + , to open it.
  yabaiPath = "/opt/homebrew/bin/yabai",
  aerospacePath = "/opt/homebrew/bin/aerospace",
  windowManager, // Window manager type (yabai or aerospace)
  shell, // Shell to use for commands
  enableServer, // Enable server mode
  yabaiServerRefresh, // Refresh rate for yabai server
} = settings.global;
const { hideWindowTitle, displayOnlyIcon, displaySkhdMode } = settings.process;

// Determine if signals should be disabled based on settings
const disableSignals = enableServer && yabaiServerRefresh;
const enableTitleChangedSignal = !hideWindowTitle && !displayOnlyIcon;

// Construct command arguments based on window manager type
const yabaiArgs = `${yabaiPath} ${displaySkhdMode} ${disableSignals} ${enableTitleChangedSignal}`;
const aerospaceArgs = `${aerospacePath}`;
const args = getArguments(windowManager, yabaiArgs, aerospaceArgs);
const command = `${shell} simple-bar/lib/scripts/init-${windowManager}.sh ${args}`;

// Inject global styles into the document
// I prefer using native CSS instead of Emotion bundled by default in Übersicht
Utils.injectStyles("simple-bar-index-styles", [
  Variables.styles,
  Base.styles,
  Spaces.styles,
  Process.styles,
  Settings.styles,
  DataWidget.styles,
  DateDisplay.styles,
  Zoom.styles,
  Time.styles,
  GitHub.styles,
  Weather.styles,
  Netstats.styles,
  Cpu.styles,
  Gpu.styles,
  Memory.styles,
  Crypto.styles,
  Stock.styles,
  Battery.styles,
  Wifi.styles,
  ViscosityVPN.styles,
  Keyboard.styles,
  Mic.styles,
  Sound.styles,
  Spotify.styles,
  YouTubeMusic.styles,
  Music.styles,
  Mpd.styles,
  BrowserTrack.styles,
  Notifications.styles,
  NextMeeting.styles,
  Specter.styles,
  Graph.styles,
  DataWidgetLoader.styles,
  settings.customStyles.styles,
  SideIcon.styles,
  Missives.styles,
]);

// Render function to display the bar
function render({ output, error }) {
  // Define base classes for the bar based on settings
  const baseClasses = Utils.classNames("simple-bar", {
    "simple-bar--floating": settings.global.floatingBar,
    "simple-bar--no-bar-background": settings.global.noBarBg,
    "simple-bar--no-color-in-data": settings.global.noColorInData,
    "simple-bar--on-bottom": settings.global.bottomBar,
    "simple-bar--inline-spaces-options": settings.global.inlineSpacesOptions,
    "simple-bar--animations-disabled": settings.global.disableAnimations,
    "simple-bar--spaces-background-color-as-foreground":
      settings.global.spacesBackgroundColorAsForeground,
    "simple-bar--widgets-background-color-as-foreground":
      settings.global.widgetsBackgroundColorAsForeground,
    "simple-bar--process-aligned-to-left": !settings.global.centered,
  });

  // Handle errors
  if (error) {
    // eslint-disable-next-line no-console
    console.error("Error in index.jsx", error);
    return <Error.Component type="error" classes={baseClasses} />;
  }
  if (!output) {
    return <Error.Component type="noOutput" classes={baseClasses} />;
  }

  // Cleanup the output data
  const cleanedUpOutput = Utils.cleanupOutput(output);

  // Handle specific errors related to yabai or AeroSpace
  const errors = ["yabaiError", "aerospaceError"];
  if (errors.includes(cleanedUpOutput)) {
    return <Error.Component type={cleanedUpOutput} classes={baseClasses} />;
  }

  // Parse the output data
  const data = Utils.parseJson(cleanedUpOutput);
  if (!data) return <Error.Component type="noData" classes={baseClasses} />;

  const { displays, shadow, skhdMode, SIP, spaces, windows } = data;

  // Check if SIP (System Integrity Protection) is disabled
  const SIPDisabled = SIP !== "System Integrity Protection status: enabled.";

  // Define additional classes based on data
  const classes = Utils.classNames(baseClasses, {
    "simple-bar--no-shadow": shadow !== "on",
  });

  // Handle bar focus ring on click
  Utils.handleBarFocus();

  // Render the bar with appropriate components and data
  return (
    <SimpleBarContextProvider
      initialSettings={settings}
      displays={displays}
      SIPDisabled={SIPDisabled}
    >
      <div className={classes}>
        <SideIcon.Component />
        <React.Suspense fallback={<React.Fragment />}>
          {windowManager === "yabai" && (
            <YabaiContextProvider
              spaces={spaces}
              windows={windows}
              skhdMode={skhdMode}
            >
              <YabaiSpaces />
              <YabaiProcess />
            </YabaiContextProvider>
          )}
          {windowManager === "aerospace" && (
            <AerospaceContextProvider>
              <AerospaceSpaces />
              <AerospaceProcess />
            </AerospaceContextProvider>
          )}
        </React.Suspense>
        <Settings.Wrapper />
        <div className="simple-bar__data">
          <UserWidgets />
          <Zoom.Widget />
          <BrowserTrack.Widget />
          <Spotify.Widget />
          <YouTubeMusic.Widget />
          <Crypto.Widget />
          <Stock.Widget />
          <Music.Widget />
          <Mpd.Widget />
          <GitHub.Widget />
          <Weather.Widget />
          <Netstats.Widget />
          <Cpu.Widget />
          <Gpu.Widget />
          <Memory.Widget />
          <Battery.Widget />
          <Notifications.Widget />
          <NextMeeting.Widget />
          <Mic.Widget />
          <Sound.Widget />
          <ViscosityVPN.Widget />
          <Wifi.Widget />
          <Keyboard.Widget />
          <DateDisplay.Widget />
          <Time.Widget />
        </div>
        <Missives.Component />
      </div>
    </SimpleBarContextProvider>
  );
}

export { command, refreshFrequency, render };

function getArguments(windowManager, yabaiArgs, aerospaceArgs) {
  if (windowManager === "yabai") {
    return yabaiArgs;
  }
  if (windowManager === "aerospace") {
    return aerospaceArgs;
  }
  return "";
}