CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/app/context.tsx
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2023 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { theme, ThemeConfig } from "antd";
7
import type { SizeType } from "antd/es/config-provider/SizeContext";
8
import { debounce } from "lodash";
9
import { createContext, ReactNode, useContext } from "react";
10
import { useIntl } from "react-intl";
11
12
import {
13
CSS,
14
useEffect,
15
useMemo,
16
useState,
17
useTypedRedux,
18
} from "@cocalc/frontend/app-framework";
19
import { COLORS } from "@cocalc/util/theme";
20
import { IntlMessage, isIntlMessage } from "@cocalc/frontend/i18n";
21
import {
22
FONT_SIZE_ICONS_NARROW,
23
FONT_SIZE_ICONS_NORMAL,
24
NARROW_THRESHOLD_PX,
25
NAV_HEIGHT_NARROW_PX,
26
NAV_HEIGHT_PX,
27
PageStyle,
28
} from "./top-nav-consts";
29
30
export interface AppState {
31
pageWidthPx: number;
32
pageStyle: PageStyle;
33
antdComponentSize?: SizeType;
34
antdTheme?: ThemeConfig;
35
formatIntl: (msg: IntlMessage | ReactNode | string) => ReactNode | string;
36
}
37
38
export const AppContext = createContext<AppState>({
39
pageWidthPx: window.innerWidth,
40
pageStyle: calcStyle(isNarrow()),
41
formatIntl: () => "Loading…",
42
});
43
44
export function useAppContext() {
45
return useContext(AppContext);
46
}
47
48
export function useAppContextProvider() {
49
const intl = useIntl();
50
51
const [pageWidthPx, setPageWidthPx] = useState<number>(window.innerWidth);
52
53
const [narrow, setNarrow] = useState<boolean>(isNarrow());
54
55
function update() {
56
setNarrow(isNarrow());
57
if (window.innerWidth != pageWidthPx) {
58
setPageWidthPx(window.innerWidth);
59
}
60
}
61
62
useEffect(() => {
63
const handleResize = debounce(update, 50, {
64
leading: false,
65
trailing: true,
66
});
67
68
window.addEventListener("resize", handleResize);
69
return () => window.removeEventListener("resize", handleResize);
70
}, []);
71
72
// avoid updating the style on every resize event
73
const pageStyle: PageStyle = useMemo(() => {
74
return calcStyle(narrow);
75
}, [narrow]);
76
77
function formatIntl(
78
msg: IntlMessage | ReactNode | string,
79
): ReactNode | string {
80
if (isIntlMessage(msg)) {
81
return intl.formatMessage(msg);
82
} else {
83
return msg;
84
}
85
}
86
87
return {
88
formatIntl,
89
pageWidthPx,
90
pageStyle,
91
};
92
}
93
94
export function useAntdStyleProvider() {
95
const other_settings = useTypedRedux("account", "other_settings");
96
const rounded = other_settings?.get("antd_rounded", true);
97
const animate = other_settings?.get("antd_animate", true);
98
const branded = other_settings?.get("antd_brandcolors", false);
99
const compact = other_settings?.get("antd_compact", false);
100
101
const borderStyle = rounded
102
? undefined
103
: { borderRadius: 0, borderRadiusLG: 0, borderRadiusSM: 0 };
104
105
const animationStyle = animate ? undefined : { motion: false };
106
107
const brandedColors = branded
108
? { colorPrimary: COLORS.COCALC_BLUE }
109
: undefined;
110
111
const algorithm = compact ? { algorithm: theme.compactAlgorithm } : undefined;
112
113
const antdTheme: ThemeConfig = {
114
...algorithm,
115
token: {
116
...brandedColors,
117
...borderStyle,
118
...animationStyle,
119
},
120
components: {
121
Button: {
122
...brandedColors,
123
},
124
},
125
};
126
127
return {
128
antdTheme,
129
};
130
}
131
132
function isNarrow(): boolean {
133
return window.innerWidth != null && window.innerWidth <= NARROW_THRESHOLD_PX;
134
}
135
136
function calcStyle(isNarrow: boolean): PageStyle {
137
const fontSizeIcons: string = isNarrow
138
? FONT_SIZE_ICONS_NARROW
139
: FONT_SIZE_ICONS_NORMAL;
140
const topPaddingIcons: string = isNarrow ? "2px" : "5px";
141
const sidePaddingIcons: string = isNarrow ? "7px" : "14px";
142
143
const height = isNarrow ? NAV_HEIGHT_NARROW_PX : NAV_HEIGHT_PX;
144
145
const topBarStyle: CSS = {
146
height: `${height}px`,
147
} as const;
148
149
const fileUseStyle: CSS = {
150
background: "white",
151
border: `2px solid ${COLORS.GRAY_DDD}`,
152
borderRadius: "5px",
153
boxShadow: "0 0 15px #aaa",
154
fontSize: "10pt",
155
height: "90%",
156
margin: 0,
157
overflowX: "hidden",
158
overflowY: "auto",
159
padding: "4px",
160
position: "fixed",
161
right: "5vw",
162
top: `${height}px`,
163
width: isNarrow ? "90vw" : "50vw",
164
zIndex: 110,
165
} as const;
166
167
const projectsNavStyle: CSS | undefined = isNarrow
168
? {
169
/* this makes it so the projects tabs are on a separate row; otherwise, there is literally no room for them at all... */
170
width: "100vw",
171
marginTop: "4px",
172
height: `${height}px`,
173
// no flex!
174
}
175
: {
176
flex: "1 1 auto", // necessary to stretch out to the full width
177
};
178
179
return {
180
topBarStyle,
181
fileUseStyle,
182
projectsNavStyle,
183
isNarrow,
184
sidePaddingIcons,
185
topPaddingIcons,
186
fontSizeIcons,
187
height,
188
};
189
}
190
191