ADD: Brightness functionality
This commit is contained in:
50
frontend/package-lock.json
generated
50
frontend/package-lock.json
generated
@@ -11,6 +11,7 @@
|
|||||||
"@stripe/react-stripe-js": "^3.1.1",
|
"@stripe/react-stripe-js": "^3.1.1",
|
||||||
"@stripe/stripe-js": "^5.5.0",
|
"@stripe/stripe-js": "^5.5.0",
|
||||||
"@types/video.js": "^7.3.58",
|
"@types/video.js": "^7.3.58",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-chrome-dino": "^0.1.3",
|
"react-chrome-dino": "^0.1.3",
|
||||||
@@ -1953,6 +1954,15 @@
|
|||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/base64-arraybuffer": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||||
@@ -2178,6 +2188,15 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-line-break": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"utrie": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cssesc": {
|
"node_modules/cssesc": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
@@ -2830,6 +2849,19 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html2canvas": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"css-line-break": "^2.1.0",
|
||||||
|
"text-segmentation": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
@@ -4233,6 +4265,15 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/text-segmentation": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"utrie": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/thenify": {
|
"node_modules/thenify": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||||
@@ -4388,6 +4429,15 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/utrie": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-arraybuffer": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/video.js": {
|
"node_modules/video.js": {
|
||||||
"version": "8.21.0",
|
"version": "8.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/video.js/-/video.js-8.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/video.js/-/video.js-8.21.0.tgz",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"@stripe/react-stripe-js": "^3.1.1",
|
"@stripe/react-stripe-js": "^3.1.1",
|
||||||
"@stripe/stripe-js": "^5.5.0",
|
"@stripe/stripe-js": "^5.5.0",
|
||||||
"@types/video.js": "^7.3.58",
|
"@types/video.js": "^7.3.58",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-chrome-dino": "^0.1.3",
|
"react-chrome-dino": "^0.1.3",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import ResultsPage from "./pages/ResultsPage";
|
|||||||
import { SidebarProvider } from "./context/SidebarContext";
|
import { SidebarProvider } from "./context/SidebarContext";
|
||||||
import { QuickSettingsProvider } from "./context/QuickSettingsContext";
|
import { QuickSettingsProvider } from "./context/QuickSettingsContext";
|
||||||
import StreamDashboardPage from "./pages/StreamDashboardPage";
|
import StreamDashboardPage from "./pages/StreamDashboardPage";
|
||||||
|
import { Brightness } from "./context/BrightnessContext";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||||
@@ -34,6 +35,7 @@ function App() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Brightness>
|
||||||
<AuthContext.Provider
|
<AuthContext.Provider
|
||||||
value={{ isLoggedIn, username, userId, setIsLoggedIn, setUsername, setUserId }}
|
value={{ isLoggedIn, username, userId, setIsLoggedIn, setUsername, setUserId }}
|
||||||
>
|
>
|
||||||
@@ -73,6 +75,7 @@ function App() {
|
|||||||
</SidebarProvider>
|
</SidebarProvider>
|
||||||
</ContentProvider>
|
</ContentProvider>
|
||||||
</AuthContext.Provider>
|
</AuthContext.Provider>
|
||||||
|
</Brightness>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import React from "react";
|
|||||||
import ThemeSetting from "./ThemeSetting";
|
import ThemeSetting from "./ThemeSetting";
|
||||||
import { useTheme } from "../../context/ThemeContext";
|
import { useTheme } from "../../context/ThemeContext";
|
||||||
import { useQuickSettings } from "../../context/QuickSettingsContext";
|
import { useQuickSettings } from "../../context/QuickSettingsContext";
|
||||||
|
import Screenshot from "../functionality/Screenshot"
|
||||||
|
import BrightnessControl from "../functionality/BrightnessControl";
|
||||||
|
|
||||||
const QuickSettings: React.FC = () => {
|
const QuickSettings: React.FC = () => {
|
||||||
const { theme } = useTheme();
|
const { theme } = useTheme();
|
||||||
@@ -19,6 +21,9 @@ const QuickSettings: React.FC = () => {
|
|||||||
<div id="quick-settings-menu" className="flex flex-col flex-grow my-8 gap-4">
|
<div id="quick-settings-menu" className="flex flex-col flex-grow my-8 gap-4">
|
||||||
<ThemeSetting />
|
<ThemeSetting />
|
||||||
</div>
|
</div>
|
||||||
|
<Screenshot />
|
||||||
|
<BrightnessControl />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
30
frontend/src/components/functionality/BrightnessControl.tsx
Normal file
30
frontend/src/components/functionality/BrightnessControl.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { useBrightness } from "../../context/BrightnessContext";
|
||||||
|
|
||||||
|
const BrightnessControl: React.FC = () => {
|
||||||
|
const { brightness, setBrightness } = useBrightness();
|
||||||
|
|
||||||
|
const handleBrightnessChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
{/* Set brightness based on the value. Calls BrightnessContext too */}
|
||||||
|
setBrightness(Number(event.target.value));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center p-4">
|
||||||
|
<h2 className="text-lg font-semibold mb-2">Brightness Control</h2>
|
||||||
|
{/* Changes based on the range of input */}
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="200"
|
||||||
|
value={brightness}
|
||||||
|
onChange={handleBrightnessChange}
|
||||||
|
className="w-60 cursor-pointer"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p className="mt-2 text-sm">Brightness: {brightness}%</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BrightnessControl;
|
||||||
50
frontend/src/components/functionality/Screenshot.tsx
Normal file
50
frontend/src/components/functionality/Screenshot.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import React from "react";
|
||||||
|
import html2canvas from "html2canvas";
|
||||||
|
|
||||||
|
const Screenshot: React.FC = () => {
|
||||||
|
const captureScreenshot = async () => {
|
||||||
|
const targetElement = document.getElementById("root"); // Capture entire HTML document
|
||||||
|
|
||||||
|
if (!targetElement) {
|
||||||
|
console.error("Target element not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Ensure everything is visible before capturing
|
||||||
|
document.body.style.overflow = "visible";
|
||||||
|
document.documentElement.style.overflow = "visible";
|
||||||
|
|
||||||
|
const canvas = await html2canvas(targetElement, {
|
||||||
|
useCORS: true, // Enables external image capture (CORS-safe)
|
||||||
|
scale: 2, // Higher resolution screenshot
|
||||||
|
backgroundColor: "#fff", // Ensures non-transparent background
|
||||||
|
windowWidth: document.documentElement.scrollWidth, // Capture full width
|
||||||
|
windowHeight: document.documentElement.scrollHeight, // Capture full height
|
||||||
|
});
|
||||||
|
|
||||||
|
// Restore overflow settings
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
document.documentElement.style.overflow = "";
|
||||||
|
|
||||||
|
const image = canvas.toDataURL("image/png");
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = image;
|
||||||
|
link.download = `screenshot-${Date.now()}.png`;
|
||||||
|
link.click();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Screenshot capture failed:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={captureScreenshot}
|
||||||
|
className="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition"
|
||||||
|
>
|
||||||
|
Capture Full Page Screenshot
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Screenshot;
|
||||||
31
frontend/src/context/BrightnessContext.tsx
Normal file
31
frontend/src/context/BrightnessContext.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import React, { createContext, useContext, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
interface BrightnessContextType {
|
||||||
|
brightness: number;
|
||||||
|
setBrightness: (value: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BrightnessContext = createContext<BrightnessContextType | undefined>(undefined);
|
||||||
|
|
||||||
|
export const Brightness: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
|
const [brightness, setBrightness] = useState<number>(100);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Apply brightness to the entire page
|
||||||
|
document.body.style.filter = `brightness(${brightness}%)`;
|
||||||
|
}, [brightness]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BrightnessContext.Provider value={{ brightness, setBrightness }}>
|
||||||
|
{children}
|
||||||
|
</BrightnessContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useBrightness = (): BrightnessContextType => {
|
||||||
|
const context = useContext(BrightnessContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useBrightness must be used within a BrightnessProvider");
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
import { StrictMode } from "react";
|
|
||||||
import { ThemeProvider } from "./context/ThemeContext";
|
import { ThemeProvider } from "./context/ThemeContext";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import "./assets/styles/index.css";
|
import "./assets/styles/index.css";
|
||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
// <StrictMode>
|
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<App />
|
<App />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
// </StrictMode>,
|
|
||||||
);
|
);
|
||||||
|
|||||||
86
package-lock.json
generated
Normal file
86
package-lock.json
generated
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"name": "cs3305-team11",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
|
"react": "^19.0.0",
|
||||||
|
"use-react-screenshot": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/base64-arraybuffer": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/css-line-break": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"utrie": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/html2canvas": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"css-line-break": "^2.1.0",
|
||||||
|
"text-segmentation": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react": {
|
||||||
|
"version": "19.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
|
||||||
|
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/text-segmentation": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"utrie": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/use-react-screenshot": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/use-react-screenshot/-/use-react-screenshot-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-4UZIORp7iCklfNOS/dPJab9SPeGdS0nFyIi3qA1rfMyYf/em/KfodYhrOlSHAHWvfdeCrS67Jjk6H4M4oLYSWg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8",
|
||||||
|
"npm": ">=5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"html2canvas": "^1.3.3",
|
||||||
|
"react": "^18.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/utrie": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-arraybuffer": "^1.0.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
package.json
Normal file
7
package.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
|
"react": "^19.0.0",
|
||||||
|
"use-react-screenshot": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user