@checkstack/ui 1.3.2 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @checkstack/ui
|
|
2
2
|
|
|
3
|
+
## 1.3.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 692c717: Increased the brightness and color intensity of the AmbientBackground auroras to ensure high visibility through the 1px grid lines.
|
|
8
|
+
|
|
9
|
+
## 1.3.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 594eecc: Implemented a manual "Low Power Mode" toggle in the user menu, allowing users to explicitly disable expensive visual effects. This replaces the previous automatic performance diagnostics with a more predictable, user-controlled system that persists to localStorage while still respecting OS-level "Reduced Motion" settings.
|
|
14
|
+
|
|
3
15
|
## 1.3.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -24,35 +24,19 @@ export const AmbientBackground: React.FC<AmbientBackgroundProps> = ({
|
|
|
24
24
|
return (
|
|
25
25
|
<>
|
|
26
26
|
<div
|
|
27
|
-
className="aurora-blob absolute w-[
|
|
27
|
+
className="aurora-blob absolute w-[100%] h-[100%] -top-[40%] -left-[20%]"
|
|
28
28
|
style={{
|
|
29
29
|
background:
|
|
30
|
-
"radial-gradient(circle at center, hsl(var(--primary) / 0.
|
|
31
|
-
animation: "aurora-float-1
|
|
30
|
+
"radial-gradient(circle at center, hsl(var(--primary) / 0.9) 0%, hsl(var(--primary) / 0.3) 50%, transparent 90%)",
|
|
31
|
+
animation: "aurora-float-1 60s ease-in-out infinite",
|
|
32
32
|
}}
|
|
33
33
|
/>
|
|
34
34
|
<div
|
|
35
|
-
className="aurora-blob absolute w-[
|
|
35
|
+
className="aurora-blob absolute w-[90%] h-[90%] -bottom-[30%] -right-[20%]"
|
|
36
36
|
style={{
|
|
37
37
|
background:
|
|
38
|
-
"radial-gradient(circle at center, hsl(var(--chart-2) / 0.
|
|
39
|
-
animation: "aurora-float-2
|
|
40
|
-
}}
|
|
41
|
-
/>
|
|
42
|
-
<div
|
|
43
|
-
className="aurora-blob absolute w-[35%] h-[35%] top-[30%] left-[40%]"
|
|
44
|
-
style={{
|
|
45
|
-
background:
|
|
46
|
-
"radial-gradient(circle at center, hsl(var(--primary) / 0.6), transparent 60%)",
|
|
47
|
-
animation: "aurora-float-3 30s ease-in-out infinite",
|
|
48
|
-
}}
|
|
49
|
-
/>
|
|
50
|
-
<div
|
|
51
|
-
className="aurora-blob absolute w-[45%] h-[45%] bottom-[20%] left-[10%]"
|
|
52
|
-
style={{
|
|
53
|
-
background:
|
|
54
|
-
"radial-gradient(circle at center, hsl(var(--chart-1) / 0.5), transparent 60%)",
|
|
55
|
-
animation: "aurora-float-4 35s ease-in-out infinite",
|
|
38
|
+
"radial-gradient(circle at center, hsl(var(--chart-2) / 0.8) 0%, hsl(var(--chart-2) / 0.2) 50%, transparent 90%)",
|
|
39
|
+
animation: "aurora-float-2 50s ease-in-out infinite",
|
|
56
40
|
}}
|
|
57
41
|
/>
|
|
58
42
|
</>
|
|
@@ -67,8 +51,10 @@ export const AmbientBackground: React.FC<AmbientBackgroundProps> = ({
|
|
|
67
51
|
)}
|
|
68
52
|
>
|
|
69
53
|
<div className="pointer-events-none fixed inset-0 overflow-hidden">
|
|
70
|
-
{/* Layer 1: Aurora Blobs (Bottom) */}
|
|
71
|
-
|
|
54
|
+
{/* Layer 1: Aurora Blobs (Bottom) - Centered in content area */}
|
|
55
|
+
<div className="max-w-7xl mx-auto h-full relative">
|
|
56
|
+
{auroraBlobs}
|
|
57
|
+
</div>
|
|
72
58
|
|
|
73
59
|
{/* Layer 2: Grid Mask - Switches mode based on performance capability */}
|
|
74
60
|
<div
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import React, { createContext, useContext, useEffect, useState } from "react";
|
|
2
2
|
|
|
3
|
+
const STORAGE_KEY = "checkstack-low-power";
|
|
4
|
+
|
|
3
5
|
interface PerformanceContextValue {
|
|
4
6
|
/**
|
|
5
|
-
* Whether the
|
|
6
|
-
*
|
|
7
|
+
* Whether the application should run in low-power mode.
|
|
8
|
+
* Derived from (manualLowPower || prefersReducedMotion).
|
|
7
9
|
*/
|
|
8
10
|
isLowPower: boolean;
|
|
9
|
-
/** Whether the performance
|
|
11
|
+
/** Whether the performance state has been initialized from storage */
|
|
10
12
|
isLoaded: boolean;
|
|
13
|
+
/** The current state of the manual toggle */
|
|
14
|
+
manualLowPower: boolean;
|
|
15
|
+
/** Toggle the manual low power setting */
|
|
16
|
+
toggleManualLowPower: () => void;
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
const PerformanceContext = createContext<PerformanceContextValue>({
|
|
14
20
|
isLowPower: false,
|
|
15
21
|
isLoaded: false,
|
|
22
|
+
manualLowPower: false,
|
|
23
|
+
toggleManualLowPower: () => {},
|
|
16
24
|
});
|
|
17
25
|
|
|
18
26
|
/**
|
|
@@ -26,99 +34,54 @@ interface PerformanceProviderProps {
|
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
/**
|
|
29
|
-
* PerformanceProvider - Centralizes
|
|
30
|
-
*
|
|
31
|
-
*
|
|
37
|
+
* PerformanceProvider - Centralizes management of the application's performance tier.
|
|
38
|
+
* Supports manual override (persisted to localStorage) and respects OS-level
|
|
39
|
+
* Reduced Motion preferences.
|
|
32
40
|
*/
|
|
33
41
|
export const PerformanceProvider: React.FC<PerformanceProviderProps> = ({ children }) => {
|
|
34
|
-
const [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
42
|
+
const [manualLowPower, setManualLowPower] = useState<boolean>(false);
|
|
43
|
+
const [prefersReducedMotion, setPrefersReducedMotion] = useState<boolean>(false);
|
|
44
|
+
const [isLoaded, setIsLoaded] = useState<boolean>(false);
|
|
38
45
|
|
|
39
46
|
useEffect(() => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
// 1. Initialize Manual Toggle from localStorage
|
|
48
|
+
const stored = globalThis.localStorage?.getItem(STORAGE_KEY);
|
|
49
|
+
if (stored === "true") {
|
|
50
|
+
setManualLowPower(true);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 2. Initialize Reduced Motion Detection
|
|
54
|
+
const mediaQuery = globalThis.matchMedia("(prefers-reduced-motion: reduce)");
|
|
55
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
(nav.deviceMemory !== undefined && nav.deviceMemory < 4) ||
|
|
50
|
-
nav.hardwareConcurrency <= 2;
|
|
57
|
+
// 3. Listen for changes in OS-level settings
|
|
58
|
+
const listener = (e: MediaQueryListEvent) => setPrefersReducedMotion(e.matches);
|
|
59
|
+
mediaQuery.addEventListener("change", listener);
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
let isSoftwareRenderer = false;
|
|
54
|
-
try {
|
|
55
|
-
const canvas = document.createElement("canvas");
|
|
56
|
-
const gl =
|
|
57
|
-
canvas.getContext("webgl") ||
|
|
58
|
-
canvas.getContext("experimental-webgl");
|
|
59
|
-
|
|
60
|
-
if (gl instanceof WebGLRenderingContext) {
|
|
61
|
-
const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
62
|
-
const renderer = (
|
|
63
|
-
debugInfo
|
|
64
|
-
? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
|
|
65
|
-
: gl.getParameter(gl.RENDERER)
|
|
66
|
-
).toLowerCase();
|
|
61
|
+
setIsLoaded(true);
|
|
67
62
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"swiftshader",
|
|
71
|
-
"llvmpipe",
|
|
72
|
-
"softpipe",
|
|
73
|
-
"swrast",
|
|
74
|
-
"osmesa",
|
|
75
|
-
"mesa off-screen",
|
|
76
|
-
"basic render",
|
|
77
|
-
"warp",
|
|
78
|
-
].some((id) => renderer.includes(id));
|
|
79
|
-
} else {
|
|
80
|
-
// No WebGL support at all usually implies old/stripped browser
|
|
81
|
-
isSoftwareRenderer = true;
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
isSoftwareRenderer = true;
|
|
85
|
-
}
|
|
63
|
+
return () => mediaQuery.removeEventListener("change", listener);
|
|
64
|
+
}, []);
|
|
86
65
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (ctx) {
|
|
95
|
-
const t0 = globalThis.performance.now();
|
|
96
|
-
ctx.filter = "blur(20px)";
|
|
97
|
-
for (let i = 0; i < 50; i++) {
|
|
98
|
-
ctx.fillRect(i, i, 5, 5);
|
|
99
|
-
}
|
|
100
|
-
// Force pipeline sync to measure actual drawing time
|
|
101
|
-
ctx.getImageData(0, 0, 1, 1);
|
|
102
|
-
const t1 = globalThis.performance.now();
|
|
103
|
-
isSlow = t1 - t0 > 4; // Threshold for CPU-based rasterization
|
|
104
|
-
}
|
|
105
|
-
} catch {
|
|
106
|
-
isSlow = true;
|
|
107
|
-
}
|
|
66
|
+
const toggleManualLowPower = () => {
|
|
67
|
+
setManualLowPower((prev) => {
|
|
68
|
+
const next = !prev;
|
|
69
|
+
globalThis.localStorage?.setItem(STORAGE_KEY, String(next));
|
|
70
|
+
return next;
|
|
71
|
+
});
|
|
72
|
+
};
|
|
108
73
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
setState({
|
|
112
|
-
isLowPower: isLowPowerVerdict,
|
|
113
|
-
isLoaded: true,
|
|
114
|
-
});
|
|
115
|
-
};
|
|
74
|
+
const isLowPower = manualLowPower || prefersReducedMotion;
|
|
116
75
|
|
|
117
|
-
|
|
118
|
-
|
|
76
|
+
const value = {
|
|
77
|
+
isLowPower,
|
|
78
|
+
isLoaded,
|
|
79
|
+
manualLowPower,
|
|
80
|
+
toggleManualLowPower,
|
|
81
|
+
};
|
|
119
82
|
|
|
120
83
|
return (
|
|
121
|
-
<PerformanceContext.Provider value={
|
|
84
|
+
<PerformanceContext.Provider value={value}>
|
|
122
85
|
{children}
|
|
123
86
|
</PerformanceContext.Provider>
|
|
124
87
|
);
|