Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/app/context.tsx
5808 views
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 { debounce } from "lodash";
8
import { ReactNode, useEffect, useMemo, useState } from "react";
9
import { useIntl } from "react-intl";
10
11
import { useTypedRedux } from "@cocalc/frontend/app-framework";
12
import { IntlMessage, isIntlMessage } from "@cocalc/frontend/i18n";
13
import { ACTIVITY_BAR_LABELS } from "@cocalc/frontend/project/page/activity-bar-consts";
14
import { A11Y } from "@cocalc/util/consts/ui";
15
import { COLORS } from "@cocalc/util/theme";
16
import { getBaseAntdTheme } from "./antd-base-theme";
17
import { NARROW_THRESHOLD_PX, PageStyle } from "./top-nav-consts";
18
import useAppContext, { AppContext, AppState, calcStyle } from "./use-context";
19
20
export { AppContext, useAppContext };
21
22
export function useAppContextProvider(): AppState {
23
const intl = useIntl();
24
const other_settings = useTypedRedux("account", "other_settings");
25
const showActBarLabels = other_settings.get(ACTIVITY_BAR_LABELS) ?? true;
26
27
const [pageWidthPx, setPageWidthPx] = useState<number>(window.innerWidth);
28
29
const [narrow, setNarrow] = useState<boolean>(isNarrow());
30
31
function update() {
32
setNarrow(isNarrow());
33
if (window.innerWidth != pageWidthPx) {
34
setPageWidthPx(window.innerWidth);
35
}
36
}
37
38
useEffect(() => {
39
const handleResize = debounce(update, 50, {
40
leading: false,
41
trailing: true,
42
});
43
44
window.addEventListener("resize", handleResize);
45
return () => window.removeEventListener("resize", handleResize);
46
}, []);
47
48
// avoid updating the style on every resize event
49
const pageStyle: PageStyle = useMemo(() => {
50
return calcStyle(narrow);
51
}, [narrow]);
52
53
function formatIntl(
54
msg: IntlMessage | ReactNode | string,
55
): ReactNode | string {
56
if (isIntlMessage(msg)) {
57
return intl.formatMessage(msg);
58
} else {
59
return msg;
60
}
61
}
62
63
function displayI18N(
64
label: string | IntlMessage | ReactNode,
65
): string | ReactNode {
66
if (isIntlMessage(label)) {
67
return intl.formatMessage(label);
68
} else {
69
return label;
70
}
71
}
72
73
return {
74
formatIntl,
75
displayI18N,
76
pageWidthPx,
77
pageStyle,
78
showActBarLabels,
79
};
80
}
81
82
export function useAntdStyleProvider() {
83
const other_settings = useTypedRedux("account", "other_settings");
84
const baseTheme = getBaseAntdTheme();
85
const rounded = other_settings?.get("antd_rounded", true);
86
const animate = other_settings?.get("antd_animate", true);
87
const branded = other_settings?.get("antd_brandcolors", false);
88
const compact = other_settings?.get("antd_compact", false);
89
90
// Parse accessibility settings
91
const accessibilityStr = other_settings?.get(A11Y);
92
let accessibilityEnabled = false;
93
if (accessibilityStr) {
94
try {
95
const accessibilitySettings = JSON.parse(accessibilityStr);
96
accessibilityEnabled = accessibilitySettings.enabled ?? false;
97
} catch {
98
// Ignore parse errors
99
}
100
}
101
102
const borderStyle = rounded
103
? undefined
104
: { borderRadius: 0, borderRadiusLG: 0, borderRadiusSM: 0 };
105
106
const animationStyle = animate ? undefined : { motion: false };
107
108
const primaryColor = branded
109
? undefined
110
: { colorPrimary: COLORS.ANTD_LINK_BLUE };
111
112
// Accessibility: Set all text to pure black for maximum contrast
113
const accessibilityTextColor = accessibilityEnabled
114
? {
115
colorText: "#000000",
116
colorTextSecondary: "#000000",
117
colorTextTertiary: "#000000",
118
colorTextQuaternary: "#000000",
119
}
120
: undefined;
121
122
const algorithm = compact ? { algorithm: theme.compactAlgorithm } : undefined;
123
124
const antdTheme: ThemeConfig = {
125
...baseTheme,
126
...algorithm,
127
token: {
128
...(baseTheme.token ?? {}),
129
...primaryColor,
130
...borderStyle,
131
...animationStyle,
132
...accessibilityTextColor,
133
},
134
components: {
135
Button: {
136
...primaryColor,
137
},
138
},
139
};
140
141
return {
142
antdTheme,
143
};
144
}
145
146
function isNarrow(): boolean {
147
return window.innerWidth != null && window.innerWidth <= NARROW_THRESHOLD_PX;
148
}
149
150