diff --git a/interface/src/App.tsx b/interface/src/App.tsx index 991ec02d..d686838b 100644 --- a/interface/src/App.tsx +++ b/interface/src/App.tsx @@ -4,9 +4,9 @@ import Settings from './pages/Settings'; import logo from './assets/betterseqta-dark-full.png'; import logoDark from './assets/betterseqta-light-full.png'; import Shortcuts from './pages/Shortcuts'; -import About from './pages/About'; import { useSettingsContext } from './SettingsContext'; import Picker from './components/Picker'; +import Themes from './pages/Themes'; const App: React.FC = () => { @@ -30,8 +30,8 @@ const App: React.FC = () => { content: }, { - title: 'About', - content: + title: 'Themes', + content: } ]; diff --git a/interface/src/pages/Themes.tsx b/interface/src/pages/Themes.tsx new file mode 100644 index 00000000..5d7793ba --- /dev/null +++ b/interface/src/pages/Themes.tsx @@ -0,0 +1,104 @@ +import React, { useState, useEffect } from 'react'; + +// IndexedDB utility functions +const openDB = () => { + return new Promise((resolve, reject) => { + const request = indexedDB.open('MyDatabase', 1); + + request.onerror = () => reject(request.error); + request.onsuccess = () => resolve(request.result); + + request.onupgradeneeded = (event) => { + const db = (event.target as IDBOpenDBRequest).result; + db.createObjectStore('backgrounds', { keyPath: 'id' }); + }; + }); +}; + +const writeData = async (type: string, data: any) => { + return new Promise((resolve, reject) => { + openDB().then(async db => { + const tx = db.transaction('backgrounds', 'readwrite'); + const store = tx.objectStore('backgrounds'); + const request = store.put({ id: 'customBackground', type, data }); + + // Wait for the transaction to complete + await new Promise((res, rej) => { + tx.oncomplete = () => res(request.result); + tx.onerror = () => rej(tx.error); + }).then(resolve, reject); + + }).catch(reject); + }); +}; + + +const readData = async () => { + const db = await openDB(); + const tx = db.transaction('backgrounds', 'readonly'); + const store = tx.objectStore('backgrounds'); + const request = store.get('customBackground'); + + return await new Promise((resolve, reject) => { + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); + }); +}; + +const Themes: React.FC = () => { + const [imageSrc, setImageSrc] = useState(null); + + const handleFileChange = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + const fileType = 'image'; + const reader = new FileReader(); + + reader.onload = async () => { + const dataURL = reader.result; + await writeData(fileType, dataURL); + setImageSrc(dataURL as string); + }; + + if (fileType === 'image') { + reader.readAsDataURL(file); + } else { + // Handle video file + } + }; + + useEffect(() => { + (async () => { + const data = await readData(); + if (data?.type === 'image') { + setImageSrc(data.data); + } + })(); + }, []); + + return ( +
+
+

Custom Background

+
+ + + {imageSrc && Uploaded content} + +
+

Themes

+
+
+ + +
+
+ ); +}; + +export default Themes; \ No newline at end of file diff --git a/src/SEQTA.js b/src/SEQTA.js index 7c3ec932..ce96b552 100644 --- a/src/SEQTA.js +++ b/src/SEQTA.js @@ -10,14 +10,17 @@ import loading, { AppendLoadingSymbol } from "./seqta/ui/Loading.js"; import assessmentsicon from "./seqta/icons/assessmentsIcon.js"; import coursesicon from "./seqta/icons/coursesIcon.js"; import StorageListener from "./seqta/utils/StorageListener.js"; +import { updateBgDurations } from "./seqta/ui/Animation.js"; +import { updateAllColors } from "./seqta/ui/Colors.js"; +import { appendBackgroundToUI } from "./seqta/ui/Background.js"; -let isChrome = window.chrome; +export let isChrome = window.chrome; let SettingsClicked = false; let MenuOptionsOpen = false; let UserInitalCode = ""; let currentSelectedDate = new Date(); let LessonInterval; -let DarkMode; +export let DarkMode; function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); @@ -36,27 +39,7 @@ function animbkEnable(item) { } } -function bkValues (item) { - const bg = document.getElementsByClassName("bg"); - const bg2 = document.getElementsByClassName("bg2"); - const bg3 = document.getElementsByClassName("bg3"); - const value = 200 - item.bksliderinput; // reverse the slider direction to match the animation direction - - if (bg.length == 0 || bg2.length == 0 || bg3.length == 0) return; - - const minDuration = 1; // minimum duration in seconds - const maxDuration = 10; // maximum duration in seconds - const durationRange = maxDuration - minDuration; - const bgDuration = minDuration + (value / 200) * durationRange; - const bg2Duration = minDuration + ((value / 200) + 0.05) * durationRange; - const bg3Duration = minDuration + ((value / 200) + 0.1) * durationRange; - - bg[0].style.animationDuration = `${bgDuration}s`; - bg2[0].style.animationDuration = `${bg2Duration}s`; - bg3[0].style.animationDuration = `${bg3Duration}s`; -} - -function ApplyCSSToHiddenMenuItems() { +export function ApplyCSSToHiddenMenuItems() { var stylesheetInnerText = ""; chrome.storage.local.get(null, function (result) { for (let i = 0; i < Object.keys(result.menuitems).length; i++) { @@ -245,7 +228,7 @@ function RemoveBackground() { bk3[0].remove(); } -function waitForElm(selector) { +export function waitForElm(selector) { return new Promise((resolve) => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); @@ -518,7 +501,7 @@ function CheckNoticeTextColour(notice) { }); } -function tryLoad() { +export function tryLoad() { waitForElm(".login").then(() => { finishLoad(); }); @@ -573,7 +556,7 @@ function ChangeMenuItemPositions(storage) { } } -async function ObserveMenuItemPosition() { +export async function ObserveMenuItemPosition() { chrome.storage.local.get(null, function (result) { let menuorder = result.menuorder; if (menuorder && result.onoff) { @@ -601,7 +584,67 @@ async function ObserveMenuItemPosition() { }); } -function AppendElementsToDisabledPage() { +function main(storedSetting) { + DarkMode = storedSetting.DarkMode; + // If the option is 'on', open BetterSEQTA + if (typeof storedSetting.onoff == "undefined") { + chrome.runtime.sendMessage({ type: "setDefaultStorage" }); + } + if (storedSetting.onoff) { + console.log("[BetterSEQTA+] Enabled"); + // Injecting CSS File to the webpage to overwrite SEQTA's default CSS + var cssFile = chrome.runtime.getURL("inject/injected.css"); + var fileref = document.createElement("link"); + fileref.setAttribute("rel", "stylesheet"); + fileref.setAttribute("type", "text/css"); + fileref.setAttribute("href", cssFile); + document.head.appendChild(fileref); + document.getElementsByTagName("html")[0].appendChild(fileref); + + // Injecting custom icons font file + const fontURL = chrome.runtime.getURL("fonts/IconFamily.woff"); + + const style = document.createElement("style"); + style.setAttribute("type", "text/css"); + style.innerHTML = ` + @font-face { + font-family: 'IconFamily'; + src: url('${fontURL}') format('woff'); + font-weight: normal; + font-style: normal; + }`; + document.head.appendChild(style); + + updateAllColors(storedSetting); + + ApplyCSSToHiddenMenuItems(); + + loading(); + + CheckLoadOnPeriods(); + + if (!isChrome || isChrome == "undefined") { + tryLoad(); + } + + window.addEventListener("load", function () { + tryLoad(); + }); + } else { + if (!isChrome || isChrome == "undefined") { + waitForElm(".code").then(() => { + AppendElementsToDisabledPage(); + }); + } + window.addEventListener("load", function () { + waitForElm(".code").then(() => { + AppendElementsToDisabledPage(); + }); + }); + } +} + +export function AppendElementsToDisabledPage() { AddBetterSEQTAElements(false); let settingsStyle = document.createElement("style"); @@ -757,146 +800,6 @@ async function CheckLoadOnPeriods() { } } -function main(storedSetting) { - DarkMode = storedSetting.DarkMode; - // If the option is 'on', open BetterSEQTA - if (typeof storedSetting.onoff == "undefined") { - chrome.runtime.sendMessage({ type: "setDefaultStorage" }); - } - if (storedSetting.onoff) { - console.log("[BetterSEQTA+] Enabled"); - // Injecting CSS File to the webpage to overwrite SEQTA's default CSS - var cssFile = chrome.runtime.getURL("inject/injected.css"); - var fileref = document.createElement("link"); - fileref.setAttribute("rel", "stylesheet"); - fileref.setAttribute("type", "text/css"); - fileref.setAttribute("href", cssFile); - document.head.appendChild(fileref); - document.getElementsByTagName("html")[0].appendChild(fileref); - - // Injecting custom icons font file - const fontURL = chrome.runtime.getURL("fonts/IconFamily.woff"); - - const style = document.createElement("style"); - style.setAttribute("type", "text/css"); - style.innerHTML = ` - @font-face { - font-family: 'IconFamily'; - src: url('${fontURL}') format('woff'); - font-weight: normal; - font-style: normal; - }`; - document.head.appendChild(style); - - - document.documentElement.style.setProperty("--better-sub", "#161616"); - document.documentElement.style.setProperty( - "--better-alert-highlight", - "#c61851", - ); - - if (storedSetting.DarkMode) { - document.documentElement.style.setProperty( - "--background-primary", - "#232323", - ); - document.documentElement.style.setProperty( - "--background-secondary", - "#1a1a1a", - ); - document.documentElement.style.setProperty("--text-primary", "white"); - } else { - try { - document.documentElement.style.setProperty( - "--better-pale", - lightenAndPaleColor(storedSetting.selectedColor), - ); - } catch (err) { - console.log(err); - } - document.documentElement.style.setProperty( - "--background-primary", - "#ffffff", - ); - document.documentElement.style.setProperty( - "--background-secondary", - "#e5e7eb", - ); - document.documentElement.style.setProperty("--text-primary", "black"); - } - - document.querySelector("link[rel*=\"icon\"]").href = - chrome.runtime.getURL("icons/icon-48.png"); - - let rbg = GetThresholdofHex(storedSetting.selectedColor); - if (rbg > 210) { - document.documentElement.style.setProperty("--text-color", "black"); - document.documentElement.style.setProperty( - "--betterseqta-logo", - `url(${chrome.runtime.getURL("icons/betterseqta-dark-full.png")})`, - ); - } else { - document.documentElement.style.setProperty("--text-color", "white"); - document.documentElement.style.setProperty( - "--betterseqta-logo", - `url(${chrome.runtime.getURL("icons/betterseqta-light-full.png")})`, - ); - } - - document.documentElement.style.setProperty( - "--better-main", - storedSetting.selectedColor, - ); - - if (storedSetting.selectedColor == "#ffffff") { - document.documentElement.style.setProperty("--better-light", "#b7b7b7"); - } else { - document.documentElement.style.setProperty( - "--better-light", - ColorLuminance(storedSetting.selectedColor, 0.95), - ); - } - - ApplyCSSToHiddenMenuItems(); - - loading(); - - CheckLoadOnPeriods(); - - if (!isChrome || isChrome == "undefined") { - tryLoad(); - } - - window.addEventListener("load", function () { - tryLoad(); - }); - } else { - if (!isChrome || isChrome == "undefined") { - waitForElm(".code").then(() => { - AppendElementsToDisabledPage(); - }); - } - window.addEventListener("load", function () { - waitForElm(".code").then(() => { - AppendElementsToDisabledPage(); - }); - }); - } -} - -async function CheckForMenuList() { - if (!MenuItemMutation) { - try { - if (document.getElementById("menu").firstChild) { - ObserveMenuItemPosition(); - MenuItemMutation = true; - } - } catch (error) { - return; - } - } -} - var MenuItemMutation = false; var NonSEQTAPage = false; var IsSEQTAPage = false; @@ -933,361 +836,8 @@ document.addEventListener( }, true, ); -/* -function RunExtensionSettingsJS() { - const whatsnewsettings = document.getElementById("whatsnewsettings"); - whatsnewsettings.addEventListener("click", function () { - if (!WhatsNewOpen) { - WhatsNewOpen = true; - OpenWhatsNewPopup(); - } - }); - - const onoffselection = document.querySelector("#onoff"); - const notificationcollector = document.querySelector("#notification"); - const lessonalert = document.querySelector("#lessonalert"); - const aboutsection = document.querySelector("#aboutsection"); - const shortcutsection = document.querySelector("#shortcutsection"); - const miscsection = document.querySelector("#miscsection"); - const colorpicker = document.querySelector("#colorpicker"); - const animatedbk = document.querySelector("#animatedbk"); - const bkslider = document.querySelector("#bksliderinput"); - - const customshortcutbutton = document.getElementsByClassName( - "custom-shortcuts-button", - )[0]; - const customshortcutdiv = document.getElementsByClassName( - "custom-shortcuts-container", - )[0]; - const customshortcutsubmit = document.getElementsByClassName( - "custom-shortcuts-submit", - )[0]; - const customshortcutinputname = document.querySelector("#shortcutname"); - const customshortcutinputurl = document.querySelector("#shortcuturl"); - - const shortcutmenuitemselection = - document.getElementsByClassName("menushortcut")[0]; - - const applybutton = document.querySelector("#applychanges"); - - const navbuttons = document.getElementsByClassName("navitem"); - const menupages = document.getElementsByClassName("menu-page"); - - const allinputs = document.getElementsByTagName("input"); - - const menupage = document.querySelector("#menupage"); - - const shortcutpage = document.querySelector("#shortcutpage"); - - const miscpage = document.querySelector("#miscpage"); - - var shortcutbuttons = document.getElementsByClassName("shortcutitem"); - - var validURL = false; - var validName = false; - - function resetActive() { - for (let i = 0; i < navbuttons.length; i++) { - navbuttons[i].classList.remove("activenav"); - } - for (let i = 0; i < menupages.length; i++) { - menupages[i].classList.add("hiddenmenu"); - } - } - - function FindSEQTATab() { - chrome.runtime.sendMessage({ type: "reloadTabs" }); - } - - // Store the currently selected settings using chrome.storage.local. - - function storeSettings() { - chrome.storage.local.set({ onoff: onoffselection.checked }, function () { - FindSEQTATab(); - }); - } - - function storeNotificationSettings() { - chrome.storage.local.set({ - notificationcollector: notificationcollector.checked, - }); - chrome.storage.local.set({ lessonalert: lessonalert.checked }); - chrome.storage.local.set({ animatedbk: animatedbk.checked }); - chrome.storage.local.set({ bksliderinput: bkslider.value }); - } - - function StoreAllSettings() { - chrome.storage.local.get(["shortcuts"], function (result) { - var shortcuts = Object.values(result)[0]; - for (var i = 0; i < shortcutbuttons.length; i++) { - shortcuts[i].enabled = shortcutbuttons[i].checked; - } - chrome.storage.local.set({ shortcuts: shortcuts }); - }); - - FindSEQTATab(); - } - - // Update the options UI with the settings values retrieved from storage, - // or the default settings if the stored settings are empty. - - function updateUI(restoredSettings) { - if (typeof restoredSettings.onoff == "undefined") { - chrome.runtime.sendMessage({ type: "setDefaultStorage" }); - - chrome.storage.local.get(null, function (result) { - updateUI(result); - }); - } else { - onoffselection.checked = restoredSettings.onoff; - notificationcollector.checked = restoredSettings.notificationcollector; - lessonalert.checked = restoredSettings.lessonalert; - animatedbk.checked = restoredSettings.animatedbk; - bkslider.value = restoredSettings.bksliderinput; - chrome.storage.local.get(["shortcuts"], function (result) { - var shortcuts = Object.values(result)[0]; - for (var i = 0; i < shortcutbuttons.length; i++) { - shortcutbuttons[i].checked = shortcuts[i].enabled; - } - chrome.storage.local.set({ shortcuts: shortcuts }); - }); - } - } - - function CreateShortcutDiv(name) { - let div = stringToHTML(` - `).firstChild; - - shortcutmenuitemselection.append(div); - - const deletebutton = document.getElementById(`delete-${name}`); - deletebutton.addEventListener("click", function () { - DeleteCustomShortcut(name); - applybutton.style.left = "4px"; - }); - } - - function AddCustomShortcuts() { - chrome.storage.local.get(["customshortcuts"], function (result) { - var customshortcuts = Object.values(result)[0]; - for (let i = 0; i < customshortcuts.length; i++) { - const element = customshortcuts[i]; - CreateShortcutDiv(element.name); - } - }); - } - - function DeleteCustomShortcut(name) { - let item = document.querySelector(`[data-customshortcut="${name}"]`); - item.remove(); - chrome.storage.local.get(["customshortcuts"], function (result) { - var customshortcuts = Object.values(result)[0]; - for (let i = 0; i < customshortcuts.length; i++) { - if (customshortcuts[i].name == name) { - customshortcuts.splice(i, 1); - } - } - chrome.storage.local.set({ customshortcuts: customshortcuts }); - }); - } - - function CustomShortcutMenu() { - customshortcutinputname.value = ""; - customshortcutinputurl.value = ""; - validURL = false; - validName = false; - customshortcutsubmit.classList.remove("customshortcut-submit-valid"); - if ( - customshortcutdiv.classList.contains("custom-shortcuts-container-shown") - ) { - customshortcutdiv.classList.remove("custom-shortcuts-container-shown"); - } else { - customshortcutdiv.classList.add("custom-shortcuts-container-shown"); - } - } - - function CreateCustomShortcut() { - const shortcutname = customshortcutinputname.value; - var shortcuturl = customshortcutinputurl.value; - - if (!shortcuturl.includes("http")) { - shortcuturl = "https://" + shortcuturl; - } - - chrome.storage.local.get(["customshortcuts"], function (result) { - var customshortcuts = Object.values(result)[0]; - customshortcuts.push({ - name: shortcutname, - url: shortcuturl, - icon: shortcutname[0].toUpperCase(), - }); - chrome.storage.local.set({ customshortcuts: customshortcuts }); - }); - - CreateShortcutDiv(shortcutname); - document.getElementsByClassName("shortcut-container")[0].style.display = - "block"; - } - - chrome.storage.local.get(null, function (result) { - document.getElementsByClassName("clr-field")[0].style.color = - result.selectedColor; - colorpicker.value = result.selectedColor; - updateUI(result); - }); - - aboutsection.addEventListener("click", () => { - resetActive(); - aboutsection.classList.add("activenav"); - menupage.classList.remove("hiddenmenu"); - }); - - shortcutsection.addEventListener("click", () => { - resetActive(); - shortcutsection.classList.add("activenav"); - shortcutpage.classList.remove("hiddenmenu"); - }); - - miscsection.addEventListener("click", () => { - resetActive(); - miscsection.classList.add("activenav"); - miscpage.classList.remove("hiddenmenu"); - }); - - customshortcutbutton.addEventListener("click", () => { - CustomShortcutMenu(); - }); - customshortcutsubmit.addEventListener("click", () => { - if (validName && validURL) { - CreateCustomShortcut(); - CustomShortcutMenu(); - } - }); - - var sameName = false; - customshortcutinputname.addEventListener("input", function () { - sameName = false; - chrome.storage.local.get(["customshortcuts"], function (result) { - var customshortcuts = Object.values(result)[0]; - for (let i = 0; i < customshortcuts.length; i++) { - if (customshortcuts[i].name == customshortcutinputname.value) { - sameName = true; - } - } - - if ( - customshortcutinputname.value.length > 0 && - customshortcutinputname.value.length < 22 && - !sameName - ) { - validName = true; - } else { - validName = false; - } - - if (validName && validURL) { - customshortcutsubmit.classList.add("customshortcut-submit-valid"); - } else { - customshortcutsubmit.classList.remove("customshortcut-submit-valid"); - } - }); - }); - - customshortcutinputurl.addEventListener("input", function () { - if ( - customshortcutinputurl.value.length > 0 && - customshortcutinputurl.value.includes(".") - ) { - validURL = true; - } else { - validURL = false; - } - - if (validName && validURL) { - customshortcutsubmit.classList.add("customshortcut-submit-valid"); - } else { - customshortcutsubmit.classList.remove("customshortcut-submit-valid"); - } - }); - - AddCustomShortcuts(); - - onoffselection.addEventListener("change", storeSettings); - notificationcollector.addEventListener("change", storeNotificationSettings); - lessonalert.addEventListener("change", storeNotificationSettings); - bkslider.addEventListener("change", () => { - storeNotificationSettings(); - chrome.storage.local.get(["bksliderinput"]).then(bkValues); - }); - animatedbk.addEventListener("change", () => { - storeNotificationSettings(); - animbkEnable({ animatedbk: animatedbk.checked }); - }); - - for (let i = 0; i < allinputs.length; i++) { - if ( - allinputs[i].id != "colorpicker" && - allinputs[i].id != "shortcuturl" && - allinputs[i].id != "shortcutname" && - allinputs[i].id != "bkslider" && - allinputs[i].id != "bksliderinput" - ) { - allinputs[i].addEventListener("change", () => { - applybutton.style.left = "4px"; - }); - } - } - - applybutton.addEventListener("click", () => { - StoreAllSettings(); - applybutton.style.left = "-150px"; - }); - - colorpicker.addEventListener("input", function () { - var colorPreview = document.querySelector("#clr-color-preview"); - if (colorPreview.style.color) { - var hex = colorPreview.style.color.split("(")[1].split(")")[0]; - hex = hex.split(","); - var b = hex.map(function (x) { - //For each array element - x = parseInt(x).toString(16); //Convert to a base16 string - return x.length == 1 ? "0" + x : x; //Add zero if we get only one character - }); - b = "#" + b.join(""); - - chrome.storage.local.set({ selectedColor: b }); - } - }); -}*/ function CallExtensionSettings() { - // Injecting CSS File to the webpage to overwrite iFrame default CSS - var cssFile = chrome.runtime.getURL("popup/info.css"); - var fileref = document.createElement("link"); - fileref.setAttribute("rel", "stylesheet"); - fileref.setAttribute("type", "text/css"); - fileref.setAttribute("href", cssFile); - document.head.append(fileref); - - var jsFile = chrome.runtime.getURL("popup/coloris.js"); - fileref = document.createElement("script"); - fileref.setAttribute("src", jsFile); - document.head.append(fileref); - - cssFile = chrome.runtime.getURL("popup/coloris.css"); - fileref = document.createElement("link"); - fileref.setAttribute("rel", "stylesheet"); - fileref.setAttribute("type", "text/css"); - fileref.setAttribute("href", cssFile); - document.head.append(fileref); - let Settings = stringToHTML( String.raw` @@ -1607,6 +1157,7 @@ function ReplaceMenuSVG(element, svg) { function AddBetterSEQTAElements(toggle) { var code = document.getElementsByClassName("code")[0]; + appendBackgroundToUI(); // Replaces students code with the version of BetterSEQTA if (code != null) { if (!code.innerHTML.includes("BetterSEQTA")) { @@ -1632,7 +1183,7 @@ function AddBetterSEQTAElements(toggle) { const sliderVal = chrome.storage.local.get(["bksliderinput"]); result.then(animbkEnable); - sliderVal.then(bkValues); + sliderVal.then(updateBgDurations); // Load darkmode state chrome.storage.local.get(["DarkMode"], function (result) { @@ -1776,7 +1327,6 @@ function AddBetterSEQTAElements(toggle) { } CallExtensionSettings(); - //RunExtensionSettingsJS(); // If betterSEQTA+ is enabled, run the code if (toggle) { @@ -3098,16 +2648,18 @@ function SendNewsPage() { }, 8); } -/* -function EnabledDisabledToBool(input) { - if (input == "enabled") { - return true; - } - if (input == "disabled") { - return false; +async function CheckForMenuList() { + if (!MenuItemMutation) { + try { + if (document.getElementById("menu").firstChild) { + ObserveMenuItemPosition(); + MenuItemMutation = true; + } + } catch (error) { + return; + } } } -*/ function LoadInit() { console.log("[BetterSEQTA] Started Init"); diff --git a/src/background.js b/src/background.js index 28133432..1016ae73 100644 --- a/src/background.js +++ b/src/background.js @@ -1,5 +1,7 @@ /*global chrome*/ +import { readData, writeData } from "./seqta/utils/IndexedDB.js"; + function ReloadSEQTAPages() { chrome.tabs.query({}, function (tabs) { for (let tab of tabs) { @@ -10,69 +12,110 @@ function ReloadSEQTAPages() { }); } -chrome.runtime.onMessage.addListener(function (request) { - if (request.type == "reloadTabs") { - ReloadSEQTAPages(); - } else if (request.type == "githubTab") { - chrome.tabs.create({ - url: "github.com/SethBurkart123/EvenBetterSEQTA", - }); - } else if (request.type == "setDefaultStorage") { - console.log("setting default values"); - SetStorageValue(DefaultValues); - } else if (request.type == "addPermissions") { - if (typeof chrome.declarativeContent != "undefined") { - chrome.declarativeContent.onPageChanged.removeRules( - undefined, - function () {}, - ); +// Helper function to handle IndexedDB actions +const handleIndexedDBActions = (request) => { + return new Promise((resolve, reject) => { + console.log("request"); + if (request.action === "save") { + writeData(request.data.type, request.data.data) + .then(() => { + resolve({ message: "Data saved successfully" }); + }) + .catch(reject); + } else if (request.action === "read") { + readData() + .then(data => { + resolve(data); + }) + .catch(reject); + } else { + reject(new Error("Invalid action type")); } - chrome.permissions.request( - { permissions: ["declarativeContent"], origins: ["*://*/*"] }, - function (granted) { - if (granted) { - let rules = [ - { - conditions: [ - new chrome.declarativeContent.PageStateMatcher({ - pageUrl: { - urlContains: "site.seqta.com.au", - schemes: ["https"], - }, - }), - ], - actions: [ - new chrome.declarativeContent.RequestContentScript({ - js: ["SEQTA.js"], - }), - ], - }, - { - conditions: [ - new chrome.declarativeContent.PageStateMatcher({ - pageUrl: { urlContains: "learn.", schemes: ["https"] }, - }), - ], - actions: [ - new chrome.declarativeContent.RequestContentScript({ - js: ["SEQTA.js"], - }), - ], - }, - ]; - for (let i = 0; i < rules.length; i++) { - chrome.declarativeContent.onPageChanged.addRules([rules[i]]); - } - alert( - "Permissions granted. Reload SEQTA pages to see changes. If this workaround doesn't work, please contact the developer. It will be an easy fix", - ); - } - }, - ); + }); +}; + +// Helper function to handle setting permissions +const handleAddPermissions = () => { + if (typeof chrome.declarativeContent !== "undefined") { + chrome.declarativeContent.onPageChanged.removeRules(undefined, () => {}); + } + + chrome.permissions.request( + { permissions: ["declarativeContent"], origins: ["*://*/*"] }, + (granted) => { + if (granted) { + const rules = [ + // Define your rules here + ]; + + rules.forEach(rule => { + chrome.declarativeContent.onPageChanged.addRules([rule]); + }); + + alert("Permissions granted. Reload SEQTA pages to see changes. If this workaround doesn't work, please contact the developer. It will be an easy fix"); + } + } + ); +}; + +// Main message listener +chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => { + console.log("Message received in background script", request); + + sendResponse({ type: "success" }); + switch (request.type) { + case "reloadTabs": + ReloadSEQTAPages(); + break; + + case "IndexedDB": + handleIndexedDBActions(request, sendResponse); + return true; // This keeps the message channel open for async sendResponse + // eslint-disable-next-line no-unreachable + break; + + case "githubTab": + chrome.tabs.create({ url: "github.com/SethBurkart123/EvenBetterSEQTA" }); + break; + + case "setDefaultStorage": + console.log("Setting default values"); + SetStorageValue(DefaultValues); + break; + + case "addPermissions": + handleAddPermissions(); + break; + + case "sendNews": + GetNews(sendResponse); + return true; + // eslint-disable-next-line no-unreachable + break; + + default: + console.log("Unknown request type"); } }); -function GetNews(url, sendResponse) { +function GetNews(sendResponse) { + // Gets the current date + const date = new Date(); + // Formats the current date used send a request for timetable and notices later + const TodayFormatted = + date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); + + const from = + date.getFullYear() + + "-" + + (date.getMonth() + 1) + + "-" + + (date.getDate() - 1); + console.log(TodayFormatted); + console.log(from); + + let url = `https://newsapi.org/v2/everything?domains=abc.net.au&from=${from}&apiKey=17c0da766ba347c89d094449504e3080`; + fetch(url) .then((result) => result.json()) .then((response) => { @@ -85,31 +128,6 @@ function GetNews(url, sendResponse) { }); } -chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { - if (request.type === "sendNews") { - // Gets the current date - const date = new Date(); - // Formats the current date used send a request for timetable and notices later - var TodayFormatted = - date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); - - var from = - date.getFullYear() + - "-" + - (date.getMonth() + 1) + - "-" + - (date.getDate() - 1); - console.log(TodayFormatted); - console.log(from); - - var url = `https://newsapi.org/v2/everything?domains=abc.net.au&from=${from}&apiKey=17c0da766ba347c89d094449504e3080`; - - GetNews(url, sendResponse); - - return true; - } -}); - const DefaultValues = { onoff: true, animatedbk: true, @@ -241,7 +259,7 @@ function migrateOldStorage() { } } - // If there's something to update, set the new values in storage + // If there"s something to update, set the new values in storage if (shouldUpdate) { chrome.storage.local.set({ shortcuts: items.shortcuts }, function() { console.log("Migration completed."); diff --git a/src/inject/iframe.css b/src/inject/iframe.css index cb4516ae..d3205e41 100644 --- a/src/inject/iframe.css +++ b/src/inject/iframe.css @@ -41,6 +41,10 @@ table th { background-color: #161616; } +/* .cke_panel_listItem { + +} */ + ::-webkit-scrollbar { width: 10px; height: 10px; diff --git a/src/inject/injected.css b/src/inject/injected.css index b2b06bc2..89a3eed8 100644 --- a/src/inject/injected.css +++ b/src/inject/injected.css @@ -1169,6 +1169,17 @@ div > ol:has(.uiFileHandlerWrapper) { border-radius: 0.5rem; } +.cke_panel > iframe { + height: 180px; + background: var(--background-primary); +} + +.cke_panel { + border-radius: 1rem; + overflow: hidden; + background: unset; +} + .Avatar__Avatar___gE5kx.Avatar__staff___4gVLs { --person-colour: var(--better-light); background: var(--person-colour, var(--navy)); diff --git a/src/inject/injected/popup.css b/src/inject/injected/popup.css index a03f151c..700f4bae 100644 --- a/src/inject/injected/popup.css +++ b/src/inject/injected/popup.css @@ -19,4 +19,10 @@ top: 80px; height: 590px; z-index: 20; +} + +.imageBackground { + width: 100%; + height: 100%; + object-fit: cover; } \ No newline at end of file diff --git a/src/seqta/ui/Animation.js b/src/seqta/ui/Animation.js new file mode 100644 index 00000000..a6059f09 --- /dev/null +++ b/src/seqta/ui/Animation.js @@ -0,0 +1,32 @@ +/** + * Update the background animation durations based on the slider input. + * @param {Object} item - The object containing the bksliderinput property. + * @param {number} [minDuration=1] - The minimum animation duration in seconds. + * @param {number} [maxDuration=10] - The maximum animation duration in seconds. + */ +export function updateBgDurations(item, minDuration = 1, maxDuration = 10) { + // Class names to look for + const bgClasses = ["bg", "bg2", "bg3"]; + + // Reverse the slider direction to align with the animation + const reversedValue = 200 - item.bksliderinput; + + // Range of possible animation durations + const durationRange = maxDuration - minDuration; + + // Function to calculate animation duration + const calcDuration = (baseValue, offset = 0) => minDuration + ((baseValue / 200) + offset) * durationRange; + + // Iterate through each class name to update its animation duration + bgClasses.forEach((className, index) => { + const elements = document.getElementsByClassName(className); + if (elements.length === 0) { + console.error(`No elements found with class name: ${className}`); + return; + } + + const offset = index * 0.05; + const duration = calcDuration(reversedValue, offset); + elements[0].style.animationDuration = `${duration}s`; + }); +} \ No newline at end of file diff --git a/src/seqta/ui/Background.js b/src/seqta/ui/Background.js new file mode 100644 index 00000000..2619d5d6 --- /dev/null +++ b/src/seqta/ui/Background.js @@ -0,0 +1,37 @@ +/* global chrome */ + +export async function appendBackgroundToUI() { + try { + const response = await new Promise((resolve, reject) => { + chrome.runtime.sendMessage({ type: "IndexedDB" }, (response) => { + if (chrome.runtime.lastError) { + return reject(chrome.runtime.lastError); + } + resolve(response); + }); + }); + console.log("response:", response); + } catch (error) { + console.log("Error:", error); + } + + + const mount = document.getElementById("container"); + console.log("Starting to append background"); + let data; + const response = await chrome.runtime.sendMessage({ type: "IndexedDB" }); + data = response; + const imgElement = document.createElement("img"); + imgElement.src = data; + imgElement.alt = "Uploaded Image"; + imgElement.classList.add("imageBackground"); + mount.appendChild(imgElement); + +/* if (data) { + continue + } else if (data?.type === "video") { + // Handle video + } */ +} + +appendBackgroundToUI(); diff --git a/src/seqta/ui/Colors.js b/src/seqta/ui/Colors.js index 406c767c..c580d6c2 100644 --- a/src/seqta/ui/Colors.js +++ b/src/seqta/ui/Colors.js @@ -1,19 +1,52 @@ /* global chrome */ -import { ColorLuminance, GetThresholdofHex } from "../../SEQTA.js"; +import { ColorLuminance, GetThresholdofHex, lightenAndPaleColor } from "../../SEQTA.js"; -export function updateDocumentColors(newColor) { - const rbg = GetThresholdofHex(newColor); - const textColor = rbg > 210 ? "black" : "white"; - const logo = `url(${chrome.runtime.getURL( - `icons/betterseqta-${textColor === "black" ? "dark" : "light"}-full.png` - )})`; +// Helper functions +const setCSSVar = (varName, value) => document.documentElement.style.setProperty(varName, value); +const getChromeURL = (path) => chrome.runtime.getURL(path); +const applyProperties = (props) => Object.entries(props).forEach(([key, value]) => setCSSVar(key, value)); - document.documentElement.style.setProperty("--text-color", textColor); - document.documentElement.style.setProperty("--betterseqta-logo", logo); - document.documentElement.style.setProperty("--better-main", newColor); +export function updateAllColors(storedSetting, newColor = null) { + // Determine the color to use + const selectedColor = newColor || storedSetting.selectedColor; + const DarkMode = storedSetting ? storedSetting.DarkMode : null; - const lightColor = - newColor === "#ffffff" ? "#b7b7b7" : ColorLuminance(newColor, 0.99); + // Common properties, always applied + const commonProps = { + "--better-sub": "#161616", + "--better-alert-highlight": "#c61851", + "--better-main": selectedColor + }; - document.documentElement.style.setProperty("--better-light", lightColor); -} \ No newline at end of file + // Mode-based properties, applied if storedSetting is provided + let modeProps = {}; + if (DarkMode !== null) { + modeProps = DarkMode ? { + "--background-primary": "#232323", + "--background-secondary": "#1a1a1a", + "--text-primary": "white" + } : { + "--background-primary": "#ffffff", + "--background-secondary": "#e5e7eb", + "--text-primary": "black", + "--better-pale": lightenAndPaleColor(selectedColor) // Wrap this in try-catch if needed + }; + } + + // Dynamic properties, always applied + const rgbThreshold = GetThresholdofHex(selectedColor); + const isBright = rgbThreshold > 210; + const dynamicProps = { + "--text-color": isBright ? "black" : "white", + "--betterseqta-logo": `url(${getChromeURL(`icons/betterseqta-${isBright ? "dark" : "light"}-full.png`)})`, + "--better-light": selectedColor === "#ffffff" ? "#b7b7b7" : ColorLuminance(selectedColor, 0.95) + }; + + // Apply all the properties + applyProperties({ ...commonProps, ...modeProps, ...dynamicProps }); + + // Set favicon, if storedSetting is provided + if (DarkMode !== null) { + document.querySelector("link[rel*='icon']").href = getChromeURL("icons/icon-48.png"); + } +} diff --git a/src/seqta/utils/IndexedDB.js b/src/seqta/utils/IndexedDB.js new file mode 100644 index 00000000..56d9446e --- /dev/null +++ b/src/seqta/utils/IndexedDB.js @@ -0,0 +1,34 @@ +// IndexedDB utility functions +export const openDB = () => { + return new Promise((resolve, reject) => { + const request = indexedDB.open("MyDatabase", 1); + + request.onerror = () => reject(request.error); + request.onsuccess = () => resolve(request.result); + + request.onupgradeneeded = (event) => { + const db = (event.target).result; + db.createObjectStore("backgrounds", { keyPath: "id" }); + }; + }); +}; + +export const writeData = async (type, data) => { + return new Promise((resolve, reject) => { + openDB().then(db => { + const tx = db.transaction("backgrounds", "readwrite"); + const store = tx.objectStore("backgrounds"); + const request = store.put({ id: "customBackground", type, data }); + + tx.oncomplete = () => resolve(request.result); + tx.onerror = () => reject(tx.error); + }).catch(reject); + }); +}; + +export const readData = async () => { + const db = await openDB(); + const tx = db.transaction("backgrounds", "readonly"); + const store = tx.objectStore("backgrounds"); + return store.get("customBackground"); +}; \ No newline at end of file diff --git a/src/seqta/utils/StorageListener.js b/src/seqta/utils/StorageListener.js index 39f9aa19..5b9e21af 100644 --- a/src/seqta/utils/StorageListener.js +++ b/src/seqta/utils/StorageListener.js @@ -4,7 +4,7 @@ import { CreateCustomShortcutDiv, RemoveCustomShortcutDiv, } from "../../SEQTA.js"; -import { updateDocumentColors } from "../ui/Colors.js"; +import { updateAllColors } from "../ui/Colors.js"; export default class StorageListener { constructor() { @@ -26,11 +26,7 @@ export default class StorageListener { handleSelectedColorChange(newColor) { try { - chrome.storage.local.get(["DarkMode"], (result) => { - if (!result.DarkMode) { - updateDocumentColors(newColor); - } - }); + updateAllColors(null, newColor); } catch (err) { console.error(err); }