aboutsummaryrefslogtreecommitdiff
path: root/users/ryan/modules/simple-bar/simple-bar-source/lib/components/simple-bar-context.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'users/ryan/modules/simple-bar/simple-bar-source/lib/components/simple-bar-context.jsx')
-rwxr-xr-xusers/ryan/modules/simple-bar/simple-bar-source/lib/components/simple-bar-context.jsx131
1 files changed, 131 insertions, 0 deletions
diff --git a/users/ryan/modules/simple-bar/simple-bar-source/lib/components/simple-bar-context.jsx b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/simple-bar-context.jsx
new file mode 100755
index 0000000..7cab27a
--- /dev/null
+++ b/users/ryan/modules/simple-bar/simple-bar-source/lib/components/simple-bar-context.jsx
@@ -0,0 +1,131 @@
1import * as Uebersicht from "uebersicht";
2import * as Aerospace from "../aerospace.js";
3
4const { React } = Uebersicht;
5
6// Create a context with default values
7const SimpleBarContext = React.createContext({
8 display: 1,
9 SIPDisabled: false,
10 settings: {},
11 setSettings: () => {},
12});
13
14/**
15 * Custom hook to use the SimpleBarContext
16 * @returns {Object} The context value
17 */
18export function useSimpleBarContext() {
19 return React.useContext(SimpleBarContext);
20}
21
22/**
23 * Provides context for simple-bar.
24 *
25 * @param {Object} props - The properties object.
26 * @param {Object} props.initialSettings - The initial settings for the application.
27 * @param {Array} props.displays - The initial displays configuration.
28 * @param {boolean} props.SIPDisabled - Indicates if SIP (System Integrity Protection) is disabled.
29 * @param {React.ReactNode} props.children - The child components to be wrapped by the provider.
30 *
31 * @returns {JSX.Element} The context provider component.
32 */
33export default function SimpleBarContextProvider({
34 initialSettings,
35 displays,
36 SIPDisabled,
37 children,
38}) {
39 const [settings, setSettings] = React.useState(initialSettings);
40 const [_displays, setDisplays] = React.useState(displays);
41 const [missives, setMissives] = React.useState([]);
42 const [ubersichtScreens, setUbersichtScreens] = React.useState([]);
43
44 const { windowManager, enableServer, yabaiServerRefresh } = settings.global;
45 const serverEnabled = enableServer && yabaiServerRefresh;
46 const isYabai = windowManager === "yabai";
47
48 const currentDisplays = serverEnabled && isYabai ? _displays : displays;
49
50 const ubersichtDisplayId = parseInt(
51 window.location.pathname.replace("/", ""),
52 10,
53 );
54
55 // Fetch Übersicht's active screen list from /state/
56 React.useEffect(() => {
57 if (isYabai) return undefined;
58
59 const controller = new AbortController();
60
61 const loadScreens = async () => {
62 try {
63 const response = await fetch("/state/", { signal: controller.signal });
64 if (!response.ok) throw new Error("Failed to load /state/");
65 const state = await response.json();
66 setUbersichtScreens(Array.isArray(state?.screens) ? state.screens : []);
67 } catch (error) {
68 if (error?.name !== "AbortError") {
69 setUbersichtScreens([]);
70 }
71 }
72 };
73
74 loadScreens();
75 return () => controller.abort();
76 }, [displays, isYabai]);
77
78 // Derive the current display rank from the active Übersicht screen order.
79 // This handles phantom displays (closed lid, previously connected monitors)
80 // that Übersicht still counts but AeroSpace doesn't report.
81 const currentScreenRank = ubersichtScreens.indexOf(ubersichtDisplayId) + 1;
82
83 // Match the current display using either the yabai display ID or AeroSpace's custom display index logic.
84 const currentDisplay =
85 currentDisplays?.find((display) =>
86 isYabai
87 ? display.id === ubersichtDisplayId
88 : Aerospace.getDisplayIndex(display) === currentScreenRank,
89 ) || {};
90
91 // Determine the display index for context value
92 // currentDisplay.index is from yabai
93 // Aerospace.getDisplayIndex is from AeroSpace with custom logic
94 // Fallback to AeroSpace monitor-appkit-nsscreen-screens-id or default to 1
95 const displayIndex =
96 currentDisplay.index ?? Aerospace.getDisplayIndex(currentDisplay) ?? 1;
97
98 const pushMissive = (newMissive) => {
99 const now = Date.now();
100 const { content, side = "right", delay = 5000 } = newMissive;
101 const timeout =
102 typeof delay === "number" && delay !== 0
103 ? setTimeout(() => {
104 setMissives((current) => {
105 return current.filter((m) => m.id !== now);
106 });
107 }, delay)
108 : undefined;
109 setMissives((current) => {
110 return [...current, { id: now, content, side, timeout }];
111 });
112 };
113
114 return (
115 <SimpleBarContext.Provider
116 value={{
117 displayIndex,
118 SIPDisabled,
119 settings,
120 setSettings,
121 displays: currentDisplays,
122 setDisplays,
123 missives,
124 setMissives,
125 pushMissive,
126 }}
127 >
128 {children}
129 </SimpleBarContext.Provider>
130 );
131}