mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
format: run prettify
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
export default /* html */`
|
||||
export default /* html */ `
|
||||
<svg style="width:24px;height:24px;border-radius:0;" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M6 20H13V22H6C4.89 22 4 21.11 4 20V4C4 2.9 4.89 2 6 2H18C19.11 2 20 2.9 20 4V12.54L18.5 11.72L18 12V4H13V12L10.5 9.75L8 12V4H6V20M24 17L18.5 14L13 17L18.5 20L24 17M15 19.09V21.09L18.5 23L22 21.09V19.09L18.5 21L15 19.09Z"></path>
|
||||
</svg>
|
||||
`;
|
||||
`;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export default /* html */`
|
||||
export default /* html */ `
|
||||
<svg style="width:24px;height:24px;border-radius:0;" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M19 1L14 6V17L19 12.5V1M21 5V18.5C19.9 18.15 18.7 18 17.5 18C15.8 18 13.35 18.65 12 19.5V6C10.55 4.9 8.45 4.5 6.5 4.5C4.55 4.5 2.45 4.9 1 6V20.65C1 20.9 1.25 21.15 1.5 21.15C1.6 21.15 1.65 21.1 1.75 21.1C3.1 20.45 5.05 20 6.5 20C8.45 20 10.55 20.4 12 21.5C13.35 20.65 15.8 20 17.5 20C19.15 20 20.85 20.3 22.25 21.05C22.35 21.1 22.4 21.1 22.5 21.1C22.75 21.1 23 20.85 23 20.6V6C22.4 5.55 21.75 5.25 21 5M10 18.41C8.75 18.09 7.5 18 6.5 18C5.44 18 4.18 18.19 3 18.5V7.13C3.91 6.73 5.14 6.5 6.5 6.5C7.86 6.5 9.09 6.73 10 7.13V18.41Z"></path>
|
||||
</svg>
|
||||
`;
|
||||
`;
|
||||
|
||||
+17
-19
@@ -1,42 +1,40 @@
|
||||
// Third-party libraries
|
||||
import browser from "webextension-polyfill"
|
||||
import browser from "webextension-polyfill";
|
||||
|
||||
// Internal utilities and functions
|
||||
import {
|
||||
settingsState,
|
||||
} from "@/seqta/utils/listeners/SettingsState"
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
||||
|
||||
// UI and theme management
|
||||
import pageState from "@/pageState.js?url"
|
||||
import pageState from "@/pageState.js?url";
|
||||
|
||||
// Stylesheets
|
||||
import injectedCSS from "@/css/injected.scss?inline"
|
||||
import injectedCSS from "@/css/injected.scss?inline";
|
||||
|
||||
export async function main() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
if (settingsState.onoff) {
|
||||
injectPageState()
|
||||
injectPageState();
|
||||
|
||||
// TEMP FIX for bug! -> this is a hack to get the injected.css file to have HMR in development mode as this import system is currently broken with crxjs
|
||||
if (import.meta.env.MODE === "development") {
|
||||
import("../css/injected.scss")
|
||||
import("../css/injected.scss");
|
||||
} else {
|
||||
const injectedStyle = document.createElement("style")
|
||||
injectedStyle.textContent = injectedCSS
|
||||
document.head.appendChild(injectedStyle)
|
||||
const injectedStyle = document.createElement("style");
|
||||
injectedStyle.textContent = injectedCSS;
|
||||
document.head.appendChild(injectedStyle);
|
||||
}
|
||||
}
|
||||
resolve(true)
|
||||
resolve(true);
|
||||
} catch (error: any) {
|
||||
console.error(error)
|
||||
reject(error)
|
||||
console.error(error);
|
||||
reject(error);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function injectPageState() {
|
||||
const mainScript = document.createElement("script")
|
||||
mainScript.src = browser.runtime.getURL(pageState)
|
||||
document.head.appendChild(mainScript)
|
||||
}
|
||||
const mainScript = document.createElement("script");
|
||||
mainScript.src = browser.runtime.getURL(pageState);
|
||||
document.head.appendChild(mainScript);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { loadHomePage } from "@/seqta/utils/Loaders/LoadHomePage";
|
||||
import { SendNewsPage } from "@/seqta/utils/SendNewsPage";
|
||||
import { setupSettingsButton } from "@/seqta/utils/setupSettingsButton";
|
||||
|
||||
|
||||
import { GetThresholdOfColor } from "@/seqta/ui/colors/getThresholdColour";
|
||||
import { appendBackgroundToUI } from "./ImageBackgrounds";
|
||||
import stringToHTML from "@/seqta/utils/stringToHTML";
|
||||
@@ -15,15 +14,15 @@ let cachedUserInfo: any = null;
|
||||
|
||||
async function getUserInfo() {
|
||||
if (cachedUserInfo) return cachedUserInfo;
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch(`${location.origin}/seqta/student/login`, {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mode: 'normal',
|
||||
mode: "normal",
|
||||
query: null,
|
||||
redirect_url: location.origin,
|
||||
}),
|
||||
@@ -33,36 +32,36 @@ async function getUserInfo() {
|
||||
cachedUserInfo = responseData.payload;
|
||||
return cachedUserInfo;
|
||||
} catch (error) {
|
||||
console.error('Error fetching user info:', error);
|
||||
console.error("Error fetching user info:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function AddBetterSEQTAElements() {
|
||||
if (settingsState.onoff) {
|
||||
if (settingsState.onoff) {
|
||||
if (settingsState.DarkMode) {
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
const menu = document.getElementById('menu')!;
|
||||
const menu = document.getElementById("menu")!;
|
||||
const menuList = menu.firstChild as HTMLElement;
|
||||
|
||||
|
||||
createHomeButton(fragment, menuList);
|
||||
createNewsButton(fragment, menu);
|
||||
|
||||
|
||||
menuList.insertBefore(fragment, menuList.firstChild);
|
||||
|
||||
|
||||
try {
|
||||
await Promise.all([
|
||||
appendBackgroundToUI(),
|
||||
handleUserInfo(),
|
||||
handleStudentData()
|
||||
handleStudentData(),
|
||||
]);
|
||||
} catch (error) {
|
||||
console.error('Error initializing UI elements:', error);
|
||||
console.error("Error initializing UI elements:", error);
|
||||
}
|
||||
|
||||
|
||||
setupEventListeners();
|
||||
await addDarkLightToggle();
|
||||
customizeMenuToggle();
|
||||
@@ -74,12 +73,14 @@ export async function AddBetterSEQTAElements() {
|
||||
}
|
||||
|
||||
function createHomeButton(fragment: DocumentFragment, menuList: HTMLElement) {
|
||||
const container = document.getElementById('content')!;
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('titlebar');
|
||||
const container = document.getElementById("content")!;
|
||||
const div = document.createElement("div");
|
||||
div.classList.add("titlebar");
|
||||
container.append(div);
|
||||
|
||||
const NewButton = stringToHTML('<li class="item" data-key="home" id="homebutton" data-path="/home" data-betterseqta="true"><label><svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z" /></svg><span>Home</span></label></li>');
|
||||
|
||||
const NewButton = stringToHTML(
|
||||
'<li class="item" data-key="home" id="homebutton" data-path="/home" data-betterseqta="true"><label><svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z" /></svg><span>Home</span></label></li>',
|
||||
);
|
||||
if (NewButton.firstChild) {
|
||||
fragment.appendChild(NewButton.firstChild);
|
||||
}
|
||||
@@ -90,7 +91,7 @@ async function handleUserInfo() {
|
||||
const info = await getUserInfo();
|
||||
updateUserInfo(info);
|
||||
} catch (error) {
|
||||
console.error('Error fetching and processing student data:', error);
|
||||
console.error("Error fetching and processing student data:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,17 +113,17 @@ function updateUserInfo(info: {
|
||||
userDesc: string | null;
|
||||
userName: string | null;
|
||||
}) {
|
||||
const titlebar = document.getElementsByClassName('titlebar')[0];
|
||||
|
||||
const userInfo = stringToHTML(/* html */`
|
||||
const titlebar = document.getElementsByClassName("titlebar")[0];
|
||||
|
||||
const userInfo = stringToHTML(/* html */ `
|
||||
<div class="userInfosvgdiv tooltip">
|
||||
<svg class="userInfosvg" viewBox="0 0 24 24"><path fill="var(--text-primary)" d="M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z"></path></svg>
|
||||
<div class="tooltiptext topmenutooltip" id="logouttooltip"></div>
|
||||
</div>
|
||||
`).firstChild;
|
||||
titlebar.append(userInfo!);
|
||||
|
||||
const userinfo = stringToHTML(/* html */`
|
||||
|
||||
const userinfo = stringToHTML(/* html */ `
|
||||
<div class="userInfo">
|
||||
<div class="userInfoText">
|
||||
<div style="display: flex; align-items: center;">
|
||||
@@ -134,27 +135,30 @@ function updateUserInfo(info: {
|
||||
</div>
|
||||
`).firstChild;
|
||||
titlebar.append(userinfo!);
|
||||
|
||||
var logoutbutton = document.getElementsByClassName('logout')[0];
|
||||
var userInfosvgdiv = document.getElementById('logouttooltip')!;
|
||||
|
||||
var logoutbutton = document.getElementsByClassName("logout")[0];
|
||||
var userInfosvgdiv = document.getElementById("logouttooltip")!;
|
||||
userInfosvgdiv.appendChild(logoutbutton);
|
||||
}
|
||||
|
||||
async function handleStudentData() {
|
||||
try {
|
||||
const response = await fetch(`${location.origin}/seqta/student/load/message/people`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
const response = await fetch(
|
||||
`${location.origin}/seqta/student/load/message/people`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
body: JSON.stringify({ mode: "student" }),
|
||||
},
|
||||
body: JSON.stringify({ mode: 'student' }),
|
||||
});
|
||||
|
||||
);
|
||||
|
||||
const responseData = await response.json();
|
||||
let students = responseData.payload;
|
||||
await updateStudentInfo(students);
|
||||
} catch (error) {
|
||||
console.error('Error fetching and processing student data:', error);
|
||||
console.error("Error fetching and processing student data:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,20 +166,21 @@ async function updateStudentInfo(students: any) {
|
||||
const info = await getUserInfo();
|
||||
var index = students.findIndex(function (person: any) {
|
||||
return (
|
||||
person.firstname == info.userDesc.split(' ')[0] &&
|
||||
person.surname == info.userDesc.split(' ')[1]
|
||||
person.firstname == info.userDesc.split(" ")[0] &&
|
||||
person.surname == info.userDesc.split(" ")[1]
|
||||
);
|
||||
});
|
||||
|
||||
let houseelement1 = document.getElementsByClassName('userInfohouse')[0];
|
||||
|
||||
let houseelement1 = document.getElementsByClassName("userInfohouse")[0];
|
||||
const houseelement = houseelement1 as HTMLElement;
|
||||
|
||||
|
||||
if (students[index]?.house) {
|
||||
if (students[index]?.house_colour) {
|
||||
houseelement.style.background = students[index].house_colour;
|
||||
try {
|
||||
let colorresult = GetThresholdOfColor(students[index]?.house_colour);
|
||||
houseelement.style.color = colorresult && colorresult > 300 ? 'black' : 'white';
|
||||
houseelement.style.color =
|
||||
colorresult && colorresult > 300 ? "black" : "white";
|
||||
houseelement.innerText = students[index].year + students[index].house;
|
||||
} catch (error) {
|
||||
houseelement.innerText = students[index].house;
|
||||
@@ -184,120 +189,133 @@ async function updateStudentInfo(students: any) {
|
||||
} else {
|
||||
try {
|
||||
houseelement.innerText = students[index].year;
|
||||
} catch(err) {
|
||||
houseelement.innerText = 'N/A';
|
||||
} catch (err) {
|
||||
houseelement.innerText = "N/A";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createNewsButton(fragment: DocumentFragment, menu: HTMLElement) {
|
||||
const NewsButtonStr = '<li class="item" data-key="news" id="newsbutton" data-path="/news" data-betterseqta="true"><label><svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M20 3H4C2.89 3 2 3.89 2 5V19C2 20.11 2.89 21 4 21H20C21.11 21 22 20.11 22 19V5C22 3.89 21.11 3 20 3M5 7H10V13H5V7M19 17H5V15H19V17M19 13H12V11H19V13M19 9H12V7H19V9Z" /></svg><span>News</span></label></li>';
|
||||
const NewsButtonStr =
|
||||
'<li class="item" data-key="news" id="newsbutton" data-path="/news" data-betterseqta="true"><label><svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M20 3H4C2.89 3 2 3.89 2 5V19C2 20.11 2.89 21 4 21H20C21.11 21 22 20.11 22 19V5C22 3.89 21.11 3 20 3M5 7H10V13H5V7M19 17H5V15H19V17M19 13H12V11H19V13M19 9H12V7H19V9Z" /></svg><span>News</span></label></li>';
|
||||
const NewsButton = stringToHTML(NewsButtonStr);
|
||||
|
||||
|
||||
if (NewsButton.firstChild) {
|
||||
fragment.appendChild(NewsButton.firstChild);
|
||||
}
|
||||
|
||||
let iconCover = document.createElement('div');
|
||||
iconCover.classList.add('icon-cover');
|
||||
iconCover.id = 'icon-cover';
|
||||
|
||||
let iconCover = document.createElement("div");
|
||||
iconCover.classList.add("icon-cover");
|
||||
iconCover.id = "icon-cover";
|
||||
menu.appendChild(iconCover);
|
||||
}
|
||||
|
||||
function setupEventListeners() {
|
||||
const menuCover = document.querySelector('#icon-cover');
|
||||
const homebutton = document.getElementById('homebutton');
|
||||
const newsbutton = document.getElementById('newsbutton');
|
||||
|
||||
homebutton?.addEventListener('click', function() {
|
||||
if (!homebutton.classList.contains('draggable') && !homebutton.classList.contains('active')) {
|
||||
const menuCover = document.querySelector("#icon-cover");
|
||||
const homebutton = document.getElementById("homebutton");
|
||||
const newsbutton = document.getElementById("newsbutton");
|
||||
|
||||
homebutton?.addEventListener("click", function () {
|
||||
if (
|
||||
!homebutton.classList.contains("draggable") &&
|
||||
!homebutton.classList.contains("active")
|
||||
) {
|
||||
loadHomePage();
|
||||
}
|
||||
});
|
||||
|
||||
newsbutton?.addEventListener('click', function() {
|
||||
if (!newsbutton.classList.contains('draggable') && !newsbutton.classList.contains('active')) {
|
||||
newsbutton?.addEventListener("click", function () {
|
||||
if (
|
||||
!newsbutton.classList.contains("draggable") &&
|
||||
!newsbutton.classList.contains("active")
|
||||
) {
|
||||
SendNewsPage();
|
||||
}
|
||||
});
|
||||
|
||||
menuCover?.addEventListener('click', function() {
|
||||
location.href = '../#?page=/home';
|
||||
menuCover?.addEventListener("click", function () {
|
||||
location.href = "../#?page=/home";
|
||||
loadHomePage();
|
||||
(document.getElementById('menu')!.firstChild! as HTMLElement).classList.remove('noscroll');
|
||||
(
|
||||
document.getElementById("menu")!.firstChild! as HTMLElement
|
||||
).classList.remove("noscroll");
|
||||
});
|
||||
}
|
||||
|
||||
async function createSettingsButton() {
|
||||
let SettingsButton = stringToHTML( /* html */`
|
||||
let SettingsButton = stringToHTML(/* html */ `
|
||||
<button class="addedButton tooltip" id="AddedSettings">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24">
|
||||
<g><g><path d="M23.182,6.923c-.29,0-3.662,2.122-4.142,2.4l-2.8-1.555V4.511l4.257-2.456a.518.518,0,0,0,.233-.408.479.479,0,0,0-.233-.407,6.511,6.511,0,1,0-3.327,12.107,6.582,6.582,0,0,0,6.148-4.374,5.228,5.228,0,0,0,.333-1.542A.461.461,0,0,0,23.182,6.923Z"></path><path d="M9.73,10.418,7.376,12.883c-.01.01-.021.016-.03.025L1.158,19.1a2.682,2.682,0,1,0,3.793,3.793l4.583-4.582,0,0,4.1-4.005-.037-.037A9.094,9.094,0,0,1,9.73,10.418ZM3.053,21.888A.894.894,0,1,1,3.946,21,.893.893,0,0,1,3.053,21.888Z"></path></g></g>
|
||||
</svg>
|
||||
${settingsState.onoff ? '<div class="tooltiptext topmenutooltip">BetterSEQTA+ Settings</div>' : ''}
|
||||
${settingsState.onoff ? '<div class="tooltiptext topmenutooltip">BetterSEQTA+ Settings</div>' : ""}
|
||||
</button>
|
||||
`);
|
||||
let ContentDiv = document.getElementById('content');
|
||||
let ContentDiv = document.getElementById("content");
|
||||
ContentDiv!.append(SettingsButton.firstChild!);
|
||||
}
|
||||
|
||||
function GetLightDarkModeString() {
|
||||
function GetLightDarkModeString() {
|
||||
if (settingsState.DarkMode) {
|
||||
return 'Switch to light theme'
|
||||
return "Switch to light theme";
|
||||
} else {
|
||||
return 'Switch to dark theme'
|
||||
return "Switch to dark theme";
|
||||
}
|
||||
}
|
||||
|
||||
async function addDarkLightToggle() {
|
||||
const tooltipString = GetLightDarkModeString();
|
||||
const svgContent = settingsState.DarkMode ?
|
||||
/* html */`<defs><clipPath id="__lottie_element_80"><rect width="24" height="24" x="0" y="0"></rect></clipPath></defs><g clip-path="url(#__lottie_element_80)"><g style="display: block;" transform="matrix(1,0,0,1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,-4 C-2.2100000381469727,-4 -4,-2.2100000381469727 -4,0 C-4,2.2100000381469727 -2.2100000381469727,4 0,4 C2.2100000381469727,4 4,2.2100000381469727 4,0 C4,-2.2100000381469727 2.2100000381469727,-4 0,-4z"></path></g></g><g style="display: block;" transform="matrix(1,0,0,1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,6 C-3.309999942779541,6 -6,3.309999942779541 -6,0 C-6,-3.309999942779541 -3.309999942779541,-6 0,-6 C3.309999942779541,-6 6,-3.309999942779541 6,0 C6,3.309999942779541 3.309999942779541,6 0,6z M8,-3.309999942779541 C8,-3.309999942779541 8,-8 8,-8 C8,-8 3.309999942779541,-8 3.309999942779541,-8 C3.309999942779541,-8 0,-11.3100004196167 0,-11.3100004196167 C0,-11.3100004196167 -3.309999942779541,-8 -3.309999942779541,-8 C-3.309999942779541,-8 -8,-8 -8,-8 C-8,-8 -8,-3.309999942779541 -8,-3.309999942779541 C-8,-3.309999942779541 -11.3100004196167,0 -11.3100004196167,0 C-11.3100004196167,0 -8,3.309999942779541 -8,3.309999942779541 C-8,3.309999942779541 -8,8 -8,8 C-8,8 -3.309999942779541,8 -3.309999942779541,8 C-3.309999942779541,8 0,11.3100004196167 0,11.3100004196167 C0,11.3100004196167 3.309999942779541,8 3.309999942779541,8 C3.309999942779541,8 8,8 8,8 C8,8 8,3.309999942779541 8,3.309999942779541 C8,3.309999942779541 11.3100004196167,0 11.3100004196167,0 C11.3100004196167,0 8,-3.309999942779541 8,-3.309999942779541z"></path></g></g></g>` :
|
||||
/* html */`<defs><clipPath id="__lottie_element_263"><rect width="24" height="24" x="0" y="0"></rect></clipPath></defs><g clip-path="url(#__lottie_element_263)"><g style="display: block;" transform="matrix(1.5,0,0,1.5,7,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,-4 C-2.2100000381469727,-4 -1.2920000553131104,-2.2100000381469727 -1.2920000553131104,0 C-1.2920000553131104,2.2100000381469727 -2.2100000381469727,4 0,4 C2.2100000381469727,4 4,2.2100000381469727 4,0 C4,-2.2100000381469727 2.2100000381469727,-4 0,-4z"></path></g></g><g style="display: block;" transform="matrix(-1,0,0,-1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,6 C-3.309999942779541,6 -6,3.309999942779541 -6,0 C-6,-3.309999942779541 -3.309999942779541,-6 0,-6 C3.309999942779541,-6 6,-3.309999942779541 6,0 C6,3.309999942779541 3.309999942779541,6 0,6z M8,-3.309999942779541 C8,-3.309999942779541 8,-8 8,-8 C8,-8 3.309999942779541,-8 3.309999942779541,-8 C3.309999942779541,-8 0,-11.3100004196167 0,-11.3100004196167 C0,-11.3100004196167 -3.309999942779541,-8 -3.309999942779541,-8 C-3.309999942779541,-8 -8,-8 -8,-8 C-8,-8 -8,-3.309999942779541 -8,-3.309999942779541 C-8,-3.309999942779541 -11.3100004196167,0 -11.3100004196167,0 C-11.3100004196167,0 -8,3.309999942779541 -8,3.309999942779541 C-8,3.309999942779541 -8,8 -8,8 C-8,8 -3.309999942779541,8 -3.309999942779541,8 C-3.309999942779541,8 0,11.3100004196167 0,11.3100004196167 C0,11.3100004196167 3.309999942779541,8 3.309999942779541,8 C3.309999942779541,8 8,8 8,8 C8,8 8,3.309999942779541 8,3.309999942779541 C8,3.309999942779541 11.3100004196167,0 11.3100004196167,0 C11.3100004196167,0 8,-3.309999942779541 8,-3.309999942779541z"></path></g></g></g>`;
|
||||
|
||||
const LightDarkModeButton = stringToHTML(/* html */`
|
||||
const svgContent = settingsState.DarkMode
|
||||
? /* html */ `<defs><clipPath id="__lottie_element_80"><rect width="24" height="24" x="0" y="0"></rect></clipPath></defs><g clip-path="url(#__lottie_element_80)"><g style="display: block;" transform="matrix(1,0,0,1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,-4 C-2.2100000381469727,-4 -4,-2.2100000381469727 -4,0 C-4,2.2100000381469727 -2.2100000381469727,4 0,4 C2.2100000381469727,4 4,2.2100000381469727 4,0 C4,-2.2100000381469727 2.2100000381469727,-4 0,-4z"></path></g></g><g style="display: block;" transform="matrix(1,0,0,1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,6 C-3.309999942779541,6 -6,3.309999942779541 -6,0 C-6,-3.309999942779541 -3.309999942779541,-6 0,-6 C3.309999942779541,-6 6,-3.309999942779541 6,0 C6,3.309999942779541 3.309999942779541,6 0,6z M8,-3.309999942779541 C8,-3.309999942779541 8,-8 8,-8 C8,-8 3.309999942779541,-8 3.309999942779541,-8 C3.309999942779541,-8 0,-11.3100004196167 0,-11.3100004196167 C0,-11.3100004196167 -3.309999942779541,-8 -3.309999942779541,-8 C-3.309999942779541,-8 -8,-8 -8,-8 C-8,-8 -8,-3.309999942779541 -8,-3.309999942779541 C-8,-3.309999942779541 -11.3100004196167,0 -11.3100004196167,0 C-11.3100004196167,0 -8,3.309999942779541 -8,3.309999942779541 C-8,3.309999942779541 -8,8 -8,8 C-8,8 -3.309999942779541,8 -3.309999942779541,8 C-3.309999942779541,8 0,11.3100004196167 0,11.3100004196167 C0,11.3100004196167 3.309999942779541,8 3.309999942779541,8 C3.309999942779541,8 8,8 8,8 C8,8 8,3.309999942779541 8,3.309999942779541 C8,3.309999942779541 11.3100004196167,0 11.3100004196167,0 C11.3100004196167,0 8,-3.309999942779541 8,-3.309999942779541z"></path></g></g></g>`
|
||||
: /* html */ `<defs><clipPath id="__lottie_element_263"><rect width="24" height="24" x="0" y="0"></rect></clipPath></defs><g clip-path="url(#__lottie_element_263)"><g style="display: block;" transform="matrix(1.5,0,0,1.5,7,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,-4 C-2.2100000381469727,-4 -1.2920000553131104,-2.2100000381469727 -1.2920000553131104,0 C-1.2920000553131104,2.2100000381469727 -2.2100000381469727,4 0,4 C2.2100000381469727,4 4,2.2100000381469727 4,0 C4,-2.2100000381469727 2.2100000381469727,-4 0,-4z"></path></g></g><g style="display: block;" transform="matrix(-1,0,0,-1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,6 C-3.309999942779541,6 -6,3.309999942779541 -6,0 C-6,-3.309999942779541 -3.309999942779541,-6 0,-6 C3.309999942779541,-6 6,-3.309999942779541 6,0 C6,3.309999942779541 3.309999942779541,6 0,6z M8,-3.309999942779541 C8,-3.309999942779541 8,-8 8,-8 C8,-8 3.309999942779541,-8 3.309999942779541,-8 C3.309999942779541,-8 0,-11.3100004196167 0,-11.3100004196167 C0,-11.3100004196167 -3.309999942779541,-8 -3.309999942779541,-8 C-3.309999942779541,-8 -8,-8 -8,-8 C-8,-8 -8,-3.309999942779541 -8,-3.309999942779541 C-8,-3.309999942779541 -11.3100004196167,0 -11.3100004196167,0 C-11.3100004196167,0 -8,3.309999942779541 -8,3.309999942779541 C-8,3.309999942779541 -8,8 -8,8 C-8,8 -3.309999942779541,8 -3.309999942779541,8 C-3.309999942779541,8 0,11.3100004196167 0,11.3100004196167 C0,11.3100004196167 3.309999942779541,8 3.309999942779541,8 C3.309999942779541,8 8,8 8,8 C8,8 8,3.309999942779541 8,3.309999942779541 C8,3.309999942779541 11.3100004196167,0 11.3100004196167,0 C11.3100004196167,0 8,-3.309999942779541 8,-3.309999942779541z"></path></g></g></g>`;
|
||||
|
||||
const LightDarkModeButton = stringToHTML(/* html */ `
|
||||
<button class="addedButton DarkLightButton tooltip" id="LightDarkModeButton">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">${svgContent}</svg>
|
||||
<div class="tooltiptext topmenutooltip" id="darklighttooliptext">${tooltipString}</div>
|
||||
</button>
|
||||
`);
|
||||
|
||||
let ContentDiv = document.getElementById('content');
|
||||
|
||||
let ContentDiv = document.getElementById("content");
|
||||
ContentDiv!.append(LightDarkModeButton.firstChild!);
|
||||
|
||||
|
||||
updateAllColors();
|
||||
|
||||
document.getElementById('LightDarkModeButton')!.addEventListener('click', async () => {
|
||||
const darklightText = document.getElementById('darklighttooliptext');
|
||||
|
||||
if (settingsState.originalDarkMode != undefined && settingsState.selectedTheme) {
|
||||
darklightText!.innerText = 'Locked by current theme';
|
||||
document
|
||||
.getElementById("LightDarkModeButton")!
|
||||
.addEventListener("click", async () => {
|
||||
const darklightText = document.getElementById("darklighttooliptext");
|
||||
|
||||
await delay(1000)
|
||||
if (
|
||||
settingsState.originalDarkMode != undefined &&
|
||||
settingsState.selectedTheme
|
||||
) {
|
||||
darklightText!.innerText = "Locked by current theme";
|
||||
|
||||
await delay(1000);
|
||||
|
||||
darklightText!.innerText = GetLightDarkModeString();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
settingsState.DarkMode = !settingsState.DarkMode;
|
||||
|
||||
updateAllColors();
|
||||
|
||||
darklightText!.innerText = GetLightDarkModeString();
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
settingsState.DarkMode = !settingsState.DarkMode;
|
||||
|
||||
updateAllColors();
|
||||
|
||||
darklightText!.innerText = GetLightDarkModeString();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function customizeMenuToggle() {
|
||||
const menuToggle = document.getElementById('menuToggle');
|
||||
const menuToggle = document.getElementById("menuToggle");
|
||||
if (menuToggle) {
|
||||
menuToggle.innerHTML = '';
|
||||
menuToggle.innerHTML = "";
|
||||
}
|
||||
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const line = document.createElement('div');
|
||||
line.className = 'hamburger-line';
|
||||
const line = document.createElement("div");
|
||||
line.className = "hamburger-line";
|
||||
menuToggle!.appendChild(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import { getDataById, isIndexedDBSupported } from '@/interface/hooks/BackgroundDataLoader';
|
||||
import {
|
||||
getDataById,
|
||||
isIndexedDBSupported,
|
||||
} from "@/interface/hooks/BackgroundDataLoader";
|
||||
|
||||
export async function appendBackgroundToUI() {
|
||||
const parent = document.getElementById('container');
|
||||
const parent = document.getElementById("container");
|
||||
if (!parent) return;
|
||||
|
||||
const backgroundContainer = document.createElement('div');
|
||||
backgroundContainer.classList.add('imageBackground');
|
||||
backgroundContainer.setAttribute('excludeDarkCheck', 'true');
|
||||
const backgroundContainer = document.createElement("div");
|
||||
backgroundContainer.classList.add("imageBackground");
|
||||
backgroundContainer.setAttribute("excludeDarkCheck", "true");
|
||||
|
||||
const mediaContainer = document.createElement('div');
|
||||
mediaContainer.id = 'media-container';
|
||||
const mediaContainer = document.createElement("div");
|
||||
mediaContainer.id = "media-container";
|
||||
backgroundContainer.appendChild(mediaContainer);
|
||||
|
||||
parent.appendChild(backgroundContainer);
|
||||
@@ -24,9 +27,9 @@ export async function loadBackground() {
|
||||
}
|
||||
|
||||
try {
|
||||
const selectedBackgroundId = localStorage.getItem('selectedBackground');
|
||||
const selectedBackgroundId = localStorage.getItem("selectedBackground");
|
||||
if (!selectedBackgroundId) {
|
||||
const backgroundContainer = document.querySelector('.imageBackground');
|
||||
const backgroundContainer = document.querySelector(".imageBackground");
|
||||
if (backgroundContainer) {
|
||||
backgroundContainer.remove();
|
||||
}
|
||||
@@ -36,35 +39,36 @@ export async function loadBackground() {
|
||||
const background = await getDataById(selectedBackgroundId);
|
||||
if (!background) return;
|
||||
|
||||
let backgroundContainer = document.querySelector('.imageBackground');
|
||||
let backgroundContainer = document.querySelector(".imageBackground");
|
||||
if (!backgroundContainer) {
|
||||
backgroundContainer = document.createElement('div');
|
||||
backgroundContainer.classList.add('imageBackground');
|
||||
backgroundContainer.setAttribute('excludeDarkCheck', 'true');
|
||||
const parent = document.getElementById('container');
|
||||
backgroundContainer = document.createElement("div");
|
||||
backgroundContainer.classList.add("imageBackground");
|
||||
backgroundContainer.setAttribute("excludeDarkCheck", "true");
|
||||
const parent = document.getElementById("container");
|
||||
if (parent) {
|
||||
parent.appendChild(backgroundContainer);
|
||||
}
|
||||
}
|
||||
|
||||
let mediaContainer = document.getElementById('media-container');
|
||||
let mediaContainer = document.getElementById("media-container");
|
||||
if (!mediaContainer) {
|
||||
mediaContainer = document.createElement('div');
|
||||
mediaContainer.id = 'media-container';
|
||||
mediaContainer = document.createElement("div");
|
||||
mediaContainer.id = "media-container";
|
||||
backgroundContainer.appendChild(mediaContainer);
|
||||
}
|
||||
|
||||
mediaContainer = document.getElementById('media-container');
|
||||
mediaContainer = document.getElementById("media-container");
|
||||
if (!mediaContainer) return;
|
||||
|
||||
mediaContainer.innerHTML = '';
|
||||
mediaContainer.innerHTML = "";
|
||||
|
||||
const mediaElement = background.type === 'video'
|
||||
? document.createElement('video')
|
||||
: document.createElement('img');
|
||||
const mediaElement =
|
||||
background.type === "video"
|
||||
? document.createElement("video")
|
||||
: document.createElement("img");
|
||||
|
||||
mediaElement.src = URL.createObjectURL(background.blob);
|
||||
mediaElement.classList.add('background');
|
||||
mediaElement.classList.add("background");
|
||||
|
||||
if (mediaElement instanceof HTMLVideoElement) {
|
||||
mediaElement.loop = true;
|
||||
@@ -74,6 +78,6 @@ export async function loadBackground() {
|
||||
|
||||
mediaContainer.appendChild(mediaElement);
|
||||
} catch (error) {
|
||||
console.error('Error loading background:', error);
|
||||
console.error("Error loading background:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-13
File diff suppressed because one or more lines are too long
@@ -6,21 +6,24 @@ import { debounce } from "lodash";
|
||||
export class SettingsResizer {
|
||||
constructor() {
|
||||
this.adjustPopupHeight();
|
||||
window.addEventListener('resize', debounce(this.adjustPopupHeight, 250) as EventListener);
|
||||
document.addEventListener('DOMContentLoaded', this.adjustPopupHeight);
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
debounce(this.adjustPopupHeight, 250) as EventListener,
|
||||
);
|
||||
document.addEventListener("DOMContentLoaded", this.adjustPopupHeight);
|
||||
}
|
||||
|
||||
private adjustPopupHeight() {
|
||||
const iframePopup = document.getElementById('ExtensionPopup');
|
||||
const iframePopup = document.getElementById("ExtensionPopup");
|
||||
if (!iframePopup) return;
|
||||
|
||||
const viewportHeight = window.innerHeight;
|
||||
const idealHeight = viewportHeight - 80 - 15; // -80px for the top of the popup
|
||||
|
||||
if (idealHeight > 600) {
|
||||
iframePopup.style.height = '600px';
|
||||
iframePopup.style.height = "600px";
|
||||
} else {
|
||||
iframePopup.style.height = `${idealHeight}px`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,48 @@
|
||||
import Color from 'color';
|
||||
import Color from "color";
|
||||
|
||||
function adjustLuminance(color: any, lum: any) {
|
||||
let adjustedColor = Color(color.toLowerCase());
|
||||
const rgbObj = adjustedColor.rgb().object();
|
||||
|
||||
|
||||
// Adjust luminance
|
||||
adjustedColor = Color.rgb(
|
||||
Math.min(Math.max(0, rgbObj.r + rgbObj.r * lum), 255),
|
||||
Math.min(Math.max(0, rgbObj.g + rgbObj.g * lum), 255),
|
||||
Math.min(Math.max(0, rgbObj.b + rgbObj.b * lum), 255)
|
||||
Math.min(Math.max(0, rgbObj.b + rgbObj.b * lum), 255),
|
||||
);
|
||||
|
||||
|
||||
return adjustedColor.string();
|
||||
}
|
||||
|
||||
export default function ColorLuminance(color: any, lum = 0) {
|
||||
if (color == '' || color == null) {
|
||||
if (color == "" || color == null) {
|
||||
// light cyan blue
|
||||
return '#00bfff';
|
||||
return "#00bfff";
|
||||
}
|
||||
const colorRegex = /rgba?\(([^)]+)\)/gi; // Case-insensitive match for rgb() or rgba()
|
||||
|
||||
if (color.toLowerCase().includes('gradient')) {
|
||||
const colorRegex = /rgba?\(([^)]+)\)/gi; // Case-insensitive match for rgb() or rgba()
|
||||
|
||||
if (color.toLowerCase().includes("gradient")) {
|
||||
let gradient = color;
|
||||
|
||||
|
||||
let uniqueColorSet = new Set();
|
||||
|
||||
|
||||
// Extract all unique color stops
|
||||
let match;
|
||||
while ((match = colorRegex.exec(color)) !== null) {
|
||||
uniqueColorSet.add(match[0]);
|
||||
}
|
||||
|
||||
|
||||
// Adjust luminance for each unique color stop
|
||||
for (let colorStop of uniqueColorSet) {
|
||||
const adjustedColor = adjustLuminance(colorStop, lum);
|
||||
gradient = gradient.replace(new RegExp(colorStop as string, 'gi'), adjustedColor);
|
||||
gradient = gradient.replace(
|
||||
new RegExp(colorStop as string, "gi"),
|
||||
adjustedColor,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return gradient;
|
||||
} else {
|
||||
return adjustLuminance(color, lum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +1,81 @@
|
||||
import browser from 'webextension-polyfill'
|
||||
import { GetThresholdOfColor } from '@/seqta/ui/colors/getThresholdColour';
|
||||
import { lightenAndPaleColor } from './lightenAndPaleColor';
|
||||
import ColorLuminance from './ColorLuminance';
|
||||
import { settingsState } from '@/seqta/utils/listeners/SettingsState';
|
||||
import browser from "webextension-polyfill";
|
||||
import { GetThresholdOfColor } from "@/seqta/ui/colors/getThresholdColour";
|
||||
import { lightenAndPaleColor } from "./lightenAndPaleColor";
|
||||
import ColorLuminance from "./ColorLuminance";
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
||||
|
||||
import darkLogo from '@/resources/icons/betterseqta-light-full.png';
|
||||
import lightLogo from '@/resources/icons/betterseqta-dark-full.png';
|
||||
import darkLogo from "@/resources/icons/betterseqta-light-full.png";
|
||||
import lightLogo from "@/resources/icons/betterseqta-dark-full.png";
|
||||
|
||||
// Helper functions
|
||||
const setCSSVar = (varName: any, value: any) => document.documentElement.style.setProperty(varName, value);
|
||||
const applyProperties = (props: any) => Object.entries(props).forEach(([key, value]) => setCSSVar(key, value));
|
||||
|
||||
const setCSSVar = (varName: any, value: any) =>
|
||||
document.documentElement.style.setProperty(varName, value);
|
||||
const applyProperties = (props: any) =>
|
||||
Object.entries(props).forEach(([key, value]) => setCSSVar(key, value));
|
||||
|
||||
export function updateAllColors() {
|
||||
// Determine the color to use
|
||||
const selectedColor = settingsState.selectedColor !== '' ? settingsState.selectedColor : '#007bff';
|
||||
const selectedColor =
|
||||
settingsState.selectedColor !== ""
|
||||
? settingsState.selectedColor
|
||||
: "#007bff";
|
||||
|
||||
if (settingsState.transparencyEffects) {
|
||||
document.documentElement.classList.add('transparencyEffects');
|
||||
document.documentElement.classList.add("transparencyEffects");
|
||||
}
|
||||
|
||||
// Common properties, always applied
|
||||
const commonProps = {
|
||||
'--better-sub': '#161616',
|
||||
'--better-alert-highlight': '#c61851',
|
||||
'--better-main': settingsState.selectedColor
|
||||
"--better-sub": "#161616",
|
||||
"--better-alert-highlight": "#c61851",
|
||||
"--better-main": settingsState.selectedColor,
|
||||
};
|
||||
|
||||
// Mode-based properties, applied if storedSetting is provided
|
||||
let modeProps = {};
|
||||
modeProps = settingsState.DarkMode ? {
|
||||
'--betterseqta-logo': `url(${browser.runtime.getURL(darkLogo)})`
|
||||
} : {
|
||||
'--better-pale': lightenAndPaleColor(selectedColor),
|
||||
'--betterseqta-logo': `url(${browser.runtime.getURL(lightLogo)})`
|
||||
};
|
||||
modeProps = settingsState.DarkMode
|
||||
? {
|
||||
"--betterseqta-logo": `url(${browser.runtime.getURL(darkLogo)})`,
|
||||
}
|
||||
: {
|
||||
"--better-pale": lightenAndPaleColor(selectedColor),
|
||||
"--betterseqta-logo": `url(${browser.runtime.getURL(lightLogo)})`,
|
||||
};
|
||||
|
||||
if (settingsState.DarkMode) {
|
||||
document.documentElement.style.removeProperty('--better-pale');
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.style.removeProperty("--better-pale");
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
|
||||
// Dynamic properties, always applied
|
||||
const rgbThreshold = GetThresholdOfColor(selectedColor);
|
||||
const isBright = rgbThreshold > 210;
|
||||
const dynamicProps = {
|
||||
'--text-color': isBright ? 'black' : 'white',
|
||||
'--better-light': selectedColor === '#ffffff' ? '#b7b7b7' : ColorLuminance(selectedColor, 0.95)
|
||||
"--text-color": isBright ? "black" : "white",
|
||||
"--better-light":
|
||||
selectedColor === "#ffffff"
|
||||
? "#b7b7b7"
|
||||
: ColorLuminance(selectedColor, 0.95),
|
||||
};
|
||||
|
||||
// Apply all the properties
|
||||
applyProperties({ ...commonProps, ...modeProps, ...dynamicProps });
|
||||
|
||||
let alliframes = document.getElementsByTagName('iframe');
|
||||
let alliframes = document.getElementsByTagName("iframe");
|
||||
|
||||
for (let i = 0; i < alliframes.length; i++) {
|
||||
const element = alliframes[i];
|
||||
|
||||
if (element.getAttribute('excludeDarkCheck') == 'true') {
|
||||
|
||||
if (element.getAttribute("excludeDarkCheck") == "true") {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (settingsState.DarkMode) {
|
||||
element.contentDocument?.documentElement.classList.add('dark');
|
||||
element.contentDocument?.documentElement.classList.add("dark");
|
||||
} else {
|
||||
element.contentDocument?.documentElement.classList.remove('dark');
|
||||
element.contentDocument?.documentElement.classList.remove("dark");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
import Color from "color"
|
||||
import Color from "color";
|
||||
export function GetThresholdOfColor(color: any) {
|
||||
if (!color) return 0
|
||||
// Case-insensitive regular expression for matching RGBA colors
|
||||
const rgbaRegex = /rgba?\(([^)]+)\)/gi
|
||||
|
||||
// Check if the color string is a gradient (linear or radial)
|
||||
if (color.includes("gradient")) {
|
||||
let gradientThresholds = []
|
||||
|
||||
// Find and replace all instances of RGBA in the gradient
|
||||
let match
|
||||
while ((match = rgbaRegex.exec(color)) !== null) {
|
||||
// Extract the individual components (r, g, b, a)
|
||||
const rgbaString = match[1]
|
||||
const [r, g, b] = rgbaString.split(",").map((str) => str.trim())
|
||||
|
||||
// Compute the threshold using your existing algorithm
|
||||
const threshold = Math.sqrt(
|
||||
parseInt(r) ** 2 + parseInt(g) ** 2 + parseInt(b) ** 2,
|
||||
)
|
||||
|
||||
// Store the computed threshold
|
||||
gradientThresholds.push(threshold)
|
||||
}
|
||||
|
||||
// Calculate the average threshold
|
||||
const averageThreshold =
|
||||
gradientThresholds.reduce((acc, val) => acc + val, 0) /
|
||||
gradientThresholds.length
|
||||
|
||||
return averageThreshold
|
||||
} else {
|
||||
// Handle the color as a simple RGBA (or hex, or whatever the Color library supports)
|
||||
const rgb = Color.rgb(color).object()
|
||||
return Math.sqrt(rgb.r ** 2 + rgb.g ** 2 + rgb.b ** 2)
|
||||
if (!color) return 0;
|
||||
// Case-insensitive regular expression for matching RGBA colors
|
||||
const rgbaRegex = /rgba?\(([^)]+)\)/gi;
|
||||
|
||||
// Check if the color string is a gradient (linear or radial)
|
||||
if (color.includes("gradient")) {
|
||||
let gradientThresholds = [];
|
||||
|
||||
// Find and replace all instances of RGBA in the gradient
|
||||
let match;
|
||||
while ((match = rgbaRegex.exec(color)) !== null) {
|
||||
// Extract the individual components (r, g, b, a)
|
||||
const rgbaString = match[1];
|
||||
const [r, g, b] = rgbaString.split(",").map((str) => str.trim());
|
||||
|
||||
// Compute the threshold using your existing algorithm
|
||||
const threshold = Math.sqrt(
|
||||
parseInt(r) ** 2 + parseInt(g) ** 2 + parseInt(b) ** 2,
|
||||
);
|
||||
|
||||
// Store the computed threshold
|
||||
gradientThresholds.push(threshold);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the average threshold
|
||||
const averageThreshold =
|
||||
gradientThresholds.reduce((acc, val) => acc + val, 0) /
|
||||
gradientThresholds.length;
|
||||
|
||||
return averageThreshold;
|
||||
} else {
|
||||
// Handle the color as a simple RGBA (or hex, or whatever the Color library supports)
|
||||
const rgb = Color.rgb(color).object();
|
||||
return Math.sqrt(rgb.r ** 2 + rgb.g ** 2 + rgb.b ** 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import Color from 'color';
|
||||
import Color from "color";
|
||||
|
||||
export function lightenAndPaleColor(inputColor: any, lightenFactor = 0.75, paleFactor = 0.55) {
|
||||
export function lightenAndPaleColor(
|
||||
inputColor: any,
|
||||
lightenFactor = 0.75,
|
||||
paleFactor = 0.55,
|
||||
) {
|
||||
if (!inputColor) return;
|
||||
|
||||
if (inputColor.includes('gradient')) {
|
||||
if (inputColor.includes("gradient")) {
|
||||
const baseColor = findMatchingColor(inputColor);
|
||||
|
||||
return lightenAndPaleColor(baseColor, lightenFactor, paleFactor);
|
||||
@@ -29,27 +33,38 @@ export function lightenAndPaleColor(inputColor: any, lightenFactor = 0.75, paleF
|
||||
}
|
||||
// Utility function to average an array of Color objects
|
||||
function averageColors(colors: any) {
|
||||
let avgR = 0, avgG = 0, avgB = 0;
|
||||
let avgR = 0,
|
||||
avgG = 0,
|
||||
avgB = 0;
|
||||
colors.forEach((color: any) => {
|
||||
avgR += color.red();
|
||||
avgG += color.green();
|
||||
avgB += color.blue();
|
||||
});
|
||||
return Color.rgb(avgR / colors.length, avgG / colors.length, avgB / colors.length);
|
||||
return Color.rgb(
|
||||
avgR / colors.length,
|
||||
avgG / colors.length,
|
||||
avgB / colors.length,
|
||||
);
|
||||
}
|
||||
// Main function to find a matching color for a CSS gradient
|
||||
function findMatchingColor(cssGradient: any) {
|
||||
try {
|
||||
// Step 1: Parse the gradient to extract color stops (case-insensitive)
|
||||
const regex = /#[0-9a-fA-F]{6}|rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)|rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)/gi;
|
||||
const regex =
|
||||
/#[0-9a-fA-F]{6}|rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)|rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)/gi;
|
||||
const colorStops = cssGradient.match(regex);
|
||||
|
||||
if (!colorStops) {
|
||||
throw new Error('No valid color stops found in the provided CSS gradient.');
|
||||
throw new Error(
|
||||
"No valid color stops found in the provided CSS gradient.",
|
||||
);
|
||||
}
|
||||
|
||||
// Normalize and trim the color stops
|
||||
const normalizedColorStops = colorStops.map((color: any) => color.toLowerCase().replace(/\s+/g, ''));
|
||||
const normalizedColorStops = colorStops.map((color: any) =>
|
||||
color.toLowerCase().replace(/\s+/g, ""),
|
||||
);
|
||||
|
||||
// Convert the color stops to Color objects
|
||||
const colorObjects = normalizedColorStops.map((color: any) => Color(color));
|
||||
@@ -57,11 +72,10 @@ function findMatchingColor(cssGradient: any) {
|
||||
// Step 2: Average the color stops
|
||||
const baseColor = averageColors(colorObjects);
|
||||
|
||||
|
||||
// Step 4: Return the matching color in HEX format
|
||||
return baseColor.hex();
|
||||
} catch (err: any) {
|
||||
console.error(`Error: ${err.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,191 +20,356 @@ function generateMockUserCode(): string {
|
||||
function getRandomDate(): Date {
|
||||
const start = new Date();
|
||||
const end = new Date(start.getTime() + 60 * 24 * 60 * 60 * 1000); // 60 days from now
|
||||
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
|
||||
return new Date(
|
||||
start.getTime() + Math.random() * (end.getTime() - start.getTime()),
|
||||
);
|
||||
}
|
||||
|
||||
const contentConfig: ContentConfig = {
|
||||
lessonTitle: {
|
||||
selector: '.day h2',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.subjects); }
|
||||
lessonTitle: {
|
||||
selector: ".day h2",
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.subjects);
|
||||
},
|
||||
},
|
||||
teacher: {
|
||||
selector: '.day h3:first-of-type',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.teachers); }
|
||||
teacher: {
|
||||
selector: ".day h3:first-of-type",
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.teachers);
|
||||
},
|
||||
},
|
||||
classroom: {
|
||||
selector: '.day h3:last-of-type',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.classrooms); }
|
||||
classroom: {
|
||||
selector: ".day h3:last-of-type",
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.classrooms);
|
||||
},
|
||||
},
|
||||
userName: {
|
||||
selector: '.userInfoName, .name',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.names); }
|
||||
userName: {
|
||||
selector: ".userInfoName, .name",
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.names);
|
||||
},
|
||||
},
|
||||
userCode: {
|
||||
selector: '.userInfoText > .userInfoCode',
|
||||
action: (element) => { element.textContent = generateMockUserCode(); }
|
||||
userCode: {
|
||||
selector: ".userInfoText > .userInfoCode",
|
||||
action: (element) => {
|
||||
element.textContent = generateMockUserCode();
|
||||
},
|
||||
},
|
||||
assessmentTitle: {
|
||||
selector: '.upcoming-assessment .upcoming-assessment-title',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.assessmentTitles); }
|
||||
assessmentTitle: {
|
||||
selector: ".upcoming-assessment .upcoming-assessment-title",
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.assessmentTitles);
|
||||
},
|
||||
},
|
||||
assessmentSubject: {
|
||||
selector: '.upcoming-assessment .upcoming-details h5',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.subjects); }
|
||||
assessmentSubject: {
|
||||
selector: ".upcoming-assessment .upcoming-details h5",
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.subjects);
|
||||
},
|
||||
},
|
||||
noticeTitle: {
|
||||
selector: '.notice h3',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.notices); }
|
||||
noticeTitle: {
|
||||
selector: ".notice h3",
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.notices);
|
||||
},
|
||||
},
|
||||
noticeContent: {
|
||||
selector: '.notice .contents',
|
||||
action: (element) => { element.textContent = 'Content has been redacted for privacy.'; }
|
||||
noticeContent: {
|
||||
selector: ".notice .contents",
|
||||
action: (element) => {
|
||||
element.textContent = "Content has been redacted for privacy.";
|
||||
},
|
||||
},
|
||||
upcomingCheckboxes: {
|
||||
selector: '.upcoming-checkbox-container',
|
||||
action: (element) => { element.firstChild!.textContent = 'SUBJ'; }
|
||||
selector: ".upcoming-checkbox-container",
|
||||
action: (element) => {
|
||||
element.firstChild!.textContent = "SUBJ";
|
||||
},
|
||||
},
|
||||
dates: {
|
||||
selector: '.upcoming-date-title h5, input[type="date"]',
|
||||
dates: {
|
||||
selector: '.upcoming-date-title h5, input[type="date"]',
|
||||
action: (element) => {
|
||||
const randomDate = getRandomDate();
|
||||
if (element instanceof HTMLInputElement) {
|
||||
element.value = randomDate.toISOString().split('T')[0];
|
||||
element.value = randomDate.toISOString().split("T")[0];
|
||||
} else {
|
||||
element.textContent = randomDate.toLocaleDateString('en-US', { weekday: 'long', day: 'numeric', month: 'long' });
|
||||
element.textContent = randomDate.toLocaleDateString("en-US", {
|
||||
weekday: "long",
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
messageSubject: {
|
||||
selector: '[class*="MessageList__subject___"]',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.messages.subjects); }
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.messages.subjects);
|
||||
},
|
||||
},
|
||||
|
||||
messageSender: {
|
||||
selector: '[class*="MessageList__value___"]',
|
||||
action: (element) => { element.textContent = getRandomElement(mockData.messages.sender); }
|
||||
action: (element) => {
|
||||
element.textContent = getRandomElement(mockData.messages.sender);
|
||||
},
|
||||
},
|
||||
|
||||
messageRecipients: {
|
||||
selector: '[class*="MessageList__recipients___"] [class*="MessageList__value___"]',
|
||||
action: (element) => { element.textContent = 'Recipient(s) Redacted'; }
|
||||
selector:
|
||||
'[class*="MessageList__recipients___"] [class*="MessageList__value___"]',
|
||||
action: (element) => {
|
||||
element.textContent = "Recipient(s) Redacted";
|
||||
},
|
||||
},
|
||||
|
||||
messageDate: {
|
||||
selector: '[class*="MessageList__date___"]',
|
||||
action: (element) => { element.textContent = getRandomDate().toLocaleDateString('en-US', { weekday: 'long', day: 'numeric', month: 'long' }); }
|
||||
action: (element) => {
|
||||
element.textContent = getRandomDate().toLocaleDateString("en-US", {
|
||||
weekday: "long",
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
});
|
||||
},
|
||||
},
|
||||
avatarImage: {
|
||||
selector: '[class*="Avatar__Avatar___"]',
|
||||
action: (element) => {
|
||||
action: (element) => {
|
||||
if (element instanceof HTMLElement) {
|
||||
element.style.removeProperty('background-image');
|
||||
element.firstChild!.firstChild!.textContent = getRandomElement(mockData.names)[0];
|
||||
element.style.removeProperty("background-image");
|
||||
element.firstChild!.firstChild!.textContent = getRandomElement(
|
||||
mockData.names,
|
||||
)[0];
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
notificationCount: {
|
||||
selector: '[class*="notifications__bubble___"]',
|
||||
action: (element) => { element.textContent = Math.floor(Math.random() * 100).toString(); }
|
||||
action: (element) => {
|
||||
element.textContent = Math.floor(Math.random() * 100).toString();
|
||||
},
|
||||
},
|
||||
schoolName: {
|
||||
selector: 'title',
|
||||
action: (element) => { element.textContent = 'School Portal'; }
|
||||
selector: "title",
|
||||
action: (element) => {
|
||||
element.textContent = "School Portal";
|
||||
},
|
||||
},
|
||||
documentNames: {
|
||||
selector: '.document td.title',
|
||||
action: (element) => { element.textContent = 'Document Name Redacted'; }
|
||||
selector: ".document td.title",
|
||||
action: (element) => {
|
||||
element.textContent = "Document Name Redacted";
|
||||
},
|
||||
},
|
||||
forumTopics: {
|
||||
selector: '#menu .sub ul li label',
|
||||
action: (element) => { element.textContent = 'Forum Topic Redacted'; }
|
||||
selector: "#menu .sub ul li label",
|
||||
action: (element) => {
|
||||
element.textContent = "Forum Topic Redacted";
|
||||
},
|
||||
},
|
||||
courseNames: {
|
||||
selector: '#menu .sub ul li[data-colour] label',
|
||||
action: (element) => { element.textContent = 'Course Name Redacted'; }
|
||||
selector: "#menu .sub ul li[data-colour] label",
|
||||
action: (element) => {
|
||||
element.textContent = "Course Name Redacted";
|
||||
},
|
||||
},
|
||||
yearGroups: {
|
||||
selector: '#menu .sub > ul > li > label',
|
||||
action: (element) => { element.textContent = 'Year Group Redacted'; }
|
||||
selector: "#menu .sub > ul > li > label",
|
||||
action: (element) => {
|
||||
element.textContent = "Year Group Redacted";
|
||||
},
|
||||
},
|
||||
newsArticleTitle: {
|
||||
selector: '.ArticleText a',
|
||||
action: (element) => { element.textContent = 'News Article Title Redacted'; }
|
||||
selector: ".ArticleText a",
|
||||
action: (element) => {
|
||||
element.textContent = "News Article Title Redacted";
|
||||
},
|
||||
},
|
||||
newsArticleContent: {
|
||||
selector: '.ArticleText p',
|
||||
action: (element) => { element.textContent = 'News Article Content Redacted'; }
|
||||
selector: ".ArticleText p",
|
||||
action: (element) => {
|
||||
element.textContent = "News Article Content Redacted";
|
||||
},
|
||||
},
|
||||
userHouse: {
|
||||
selector: '.userInfohouse',
|
||||
action: (element) => { element.textContent = 'House'; }
|
||||
}
|
||||
selector: ".userInfohouse",
|
||||
action: (element) => {
|
||||
element.textContent = "House";
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mockData = {
|
||||
subjects: [
|
||||
"Mathematics", "English", "Science", "History", "Geography",
|
||||
"Art", "Music", "Physical Education", "Chemistry", "Physics",
|
||||
"Biology", "Economics", "Business Studies", "French", "Spanish",
|
||||
"Computer Science", "Literature", "Environmental Studies",
|
||||
"Political Science", "Sociology"
|
||||
"Mathematics",
|
||||
"English",
|
||||
"Science",
|
||||
"History",
|
||||
"Geography",
|
||||
"Art",
|
||||
"Music",
|
||||
"Physical Education",
|
||||
"Chemistry",
|
||||
"Physics",
|
||||
"Biology",
|
||||
"Economics",
|
||||
"Business Studies",
|
||||
"French",
|
||||
"Spanish",
|
||||
"Computer Science",
|
||||
"Literature",
|
||||
"Environmental Studies",
|
||||
"Political Science",
|
||||
"Sociology",
|
||||
],
|
||||
teachers: [
|
||||
"Mr. Smith", "Mrs. Johnson", "Ms. Williams", "Dr. Brown",
|
||||
"Mr. Davis", "Mrs. Miller", "Mr. Wilson", "Ms. Moore",
|
||||
"Dr. Taylor", "Mrs. Anderson", "Mr. Garcia", "Mrs. Martinez",
|
||||
"Ms. Thompson", "Dr. Lee", "Mr. Robinson", "Mrs. Hall",
|
||||
"Ms. White", "Dr. Clark", "Mr. Lewis", "Mrs. King"
|
||||
"Mr. Smith",
|
||||
"Mrs. Johnson",
|
||||
"Ms. Williams",
|
||||
"Dr. Brown",
|
||||
"Mr. Davis",
|
||||
"Mrs. Miller",
|
||||
"Mr. Wilson",
|
||||
"Ms. Moore",
|
||||
"Dr. Taylor",
|
||||
"Mrs. Anderson",
|
||||
"Mr. Garcia",
|
||||
"Mrs. Martinez",
|
||||
"Ms. Thompson",
|
||||
"Dr. Lee",
|
||||
"Mr. Robinson",
|
||||
"Mrs. Hall",
|
||||
"Ms. White",
|
||||
"Dr. Clark",
|
||||
"Mr. Lewis",
|
||||
"Mrs. King",
|
||||
],
|
||||
classrooms: [
|
||||
"A101", "B205", "C304", "D102", "E201",
|
||||
"F103", "G204", "H301", "I202", "J105",
|
||||
"K107", "L206", "M303", "N104", "O209"
|
||||
"A101",
|
||||
"B205",
|
||||
"C304",
|
||||
"D102",
|
||||
"E201",
|
||||
"F103",
|
||||
"G204",
|
||||
"H301",
|
||||
"I202",
|
||||
"J105",
|
||||
"K107",
|
||||
"L206",
|
||||
"M303",
|
||||
"N104",
|
||||
"O209",
|
||||
],
|
||||
names: [
|
||||
"John Doe", "Jane Smith", "Michael Johnson", "Emily Brown",
|
||||
"David Lee", "Sarah Davis", "Robert Wilson", "Lisa Taylor",
|
||||
"William Moore", "Jennifer Anderson", "Thomas Garcia",
|
||||
"Olivia Martinez", "Daniel Thompson", "Sophia Lee",
|
||||
"Matthew Robinson", "Ava Hall", "Jacob White",
|
||||
"Mia Clark", "James Lewis", "Lily King"
|
||||
"John Doe",
|
||||
"Jane Smith",
|
||||
"Michael Johnson",
|
||||
"Emily Brown",
|
||||
"David Lee",
|
||||
"Sarah Davis",
|
||||
"Robert Wilson",
|
||||
"Lisa Taylor",
|
||||
"William Moore",
|
||||
"Jennifer Anderson",
|
||||
"Thomas Garcia",
|
||||
"Olivia Martinez",
|
||||
"Daniel Thompson",
|
||||
"Sophia Lee",
|
||||
"Matthew Robinson",
|
||||
"Ava Hall",
|
||||
"Jacob White",
|
||||
"Mia Clark",
|
||||
"James Lewis",
|
||||
"Lily King",
|
||||
],
|
||||
assessmentTitles: [
|
||||
"Mid-term Exam", "Final Project", "Research Paper",
|
||||
"Oral Presentation", "Lab Report", "Essay",
|
||||
"Group Assignment", "Portfolio Review", "Quiz",
|
||||
"Practical Test", "Class Presentation",
|
||||
"Online Assessment", "Case Study", "Field Report",
|
||||
"Peer Review", "Coding Challenge", "Math Test",
|
||||
"Literary Analysis", "Debate", "Design Project"
|
||||
"Mid-term Exam",
|
||||
"Final Project",
|
||||
"Research Paper",
|
||||
"Oral Presentation",
|
||||
"Lab Report",
|
||||
"Essay",
|
||||
"Group Assignment",
|
||||
"Portfolio Review",
|
||||
"Quiz",
|
||||
"Practical Test",
|
||||
"Class Presentation",
|
||||
"Online Assessment",
|
||||
"Case Study",
|
||||
"Field Report",
|
||||
"Peer Review",
|
||||
"Coding Challenge",
|
||||
"Math Test",
|
||||
"Literary Analysis",
|
||||
"Debate",
|
||||
"Design Project",
|
||||
],
|
||||
notices: [
|
||||
"School Assembly", "Excursion Reminder", "Fundraising Event",
|
||||
"Parent-Teacher Meetings", "Sports Day", "Book Fair",
|
||||
"Career Day", "Music Concert", "Art Exhibition",
|
||||
"Science Fair", "Holiday Celebration", "Community Service Day",
|
||||
"Graduation Ceremony", "Award Ceremony", "Workshop",
|
||||
"Open House", "Seminar", "Club Meeting",
|
||||
"Field Trip", "Cultural Festival"
|
||||
"School Assembly",
|
||||
"Excursion Reminder",
|
||||
"Fundraising Event",
|
||||
"Parent-Teacher Meetings",
|
||||
"Sports Day",
|
||||
"Book Fair",
|
||||
"Career Day",
|
||||
"Music Concert",
|
||||
"Art Exhibition",
|
||||
"Science Fair",
|
||||
"Holiday Celebration",
|
||||
"Community Service Day",
|
||||
"Graduation Ceremony",
|
||||
"Award Ceremony",
|
||||
"Workshop",
|
||||
"Open House",
|
||||
"Seminar",
|
||||
"Club Meeting",
|
||||
"Field Trip",
|
||||
"Cultural Festival",
|
||||
],
|
||||
messages: {
|
||||
subjects: [
|
||||
"Mid-year Exams", "Science project due soon", "Mufti Day coming up!",
|
||||
"School Assembly", "Excursion Reminder", "Fundraising Event",
|
||||
"Parent-Teacher Meetings", "Sports Day", "Book Fair",
|
||||
"Career Day", "Music Concert", "Art Exhibition",
|
||||
"Science Fair", "Holiday Celebration", "Community Service Day",
|
||||
"Graduation Ceremony", "Award Ceremony", "Workshop",
|
||||
"Open House", "Seminar", "Club Meeting",
|
||||
"Field Trip", "Cultural Festival"
|
||||
"Mid-year Exams",
|
||||
"Science project due soon",
|
||||
"Mufti Day coming up!",
|
||||
"School Assembly",
|
||||
"Excursion Reminder",
|
||||
"Fundraising Event",
|
||||
"Parent-Teacher Meetings",
|
||||
"Sports Day",
|
||||
"Book Fair",
|
||||
"Career Day",
|
||||
"Music Concert",
|
||||
"Art Exhibition",
|
||||
"Science Fair",
|
||||
"Holiday Celebration",
|
||||
"Community Service Day",
|
||||
"Graduation Ceremony",
|
||||
"Award Ceremony",
|
||||
"Workshop",
|
||||
"Open House",
|
||||
"Seminar",
|
||||
"Club Meeting",
|
||||
"Field Trip",
|
||||
"Cultural Festival",
|
||||
],
|
||||
sender: [
|
||||
"Mr. Smith", "Mrs. Johnson", "Ms. Williams", "Dr. Brown",
|
||||
"Mr. Davis", "Mrs. Miller", "Mr. Wilson", "Ms. Moore",
|
||||
"Dr. Taylor", "Mrs. Anderson", "Mr. Garcia", "Mrs. Martinez",
|
||||
]
|
||||
}
|
||||
"Mr. Smith",
|
||||
"Mrs. Johnson",
|
||||
"Ms. Williams",
|
||||
"Dr. Brown",
|
||||
"Mr. Davis",
|
||||
"Mrs. Miller",
|
||||
"Mr. Wilson",
|
||||
"Ms. Moore",
|
||||
"Dr. Taylor",
|
||||
"Mrs. Anderson",
|
||||
"Mr. Garcia",
|
||||
"Mrs. Martinez",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default function hideSensitiveContent() {
|
||||
@@ -214,4 +379,4 @@ export default function hideSensitiveContent() {
|
||||
action(element);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+17
-17
@@ -1,35 +1,35 @@
|
||||
import renderSvelte from '@/interface/main';
|
||||
import Store from '@/interface/pages/store.svelte'
|
||||
import renderSvelte from "@/interface/main";
|
||||
import Store from "@/interface/pages/store.svelte";
|
||||
|
||||
import { unmount } from 'svelte'
|
||||
import { unmount } from "svelte";
|
||||
|
||||
let remove: () => void
|
||||
let remove: () => void;
|
||||
|
||||
export function OpenStorePage() {
|
||||
remove = renderStore()
|
||||
remove = renderStore();
|
||||
}
|
||||
|
||||
export function renderStore() {
|
||||
const container = document.querySelector('#container');
|
||||
const container = document.querySelector("#container");
|
||||
if (!container) {
|
||||
throw new Error('Container not found');
|
||||
throw new Error("Container not found");
|
||||
}
|
||||
|
||||
const child = document.createElement('div');
|
||||
child.id = 'store';
|
||||
|
||||
const child = document.createElement("div");
|
||||
child.id = "store";
|
||||
container!.appendChild(child);
|
||||
|
||||
const shadow = child.attachShadow({ mode: 'open' });
|
||||
const shadow = child.attachShadow({ mode: "open" });
|
||||
const app = renderSvelte(Store, shadow);
|
||||
|
||||
return () => unmount(app)
|
||||
return () => unmount(app);
|
||||
}
|
||||
|
||||
export function closeStore() {
|
||||
document.getElementById('store')!.classList.add('hide')
|
||||
document.getElementById("store")!.classList.add("hide");
|
||||
|
||||
setTimeout(() => {
|
||||
remove()
|
||||
document.getElementById('store')!.remove()
|
||||
}, 500)
|
||||
setTimeout(() => {
|
||||
remove();
|
||||
document.getElementById("store")!.remove();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
@@ -1,36 +1,40 @@
|
||||
import { changeSettingsClicked, closeExtensionPopup, SettingsClicked } from "../Closers/closeExtensionPopup"
|
||||
import renderSvelte from "@/interface/main"
|
||||
import { SettingsResizer } from "@/seqta/ui/SettingsResizer"
|
||||
import Settings from "@/interface/pages/settings.svelte"
|
||||
import {
|
||||
changeSettingsClicked,
|
||||
closeExtensionPopup,
|
||||
SettingsClicked,
|
||||
} from "../Closers/closeExtensionPopup";
|
||||
import renderSvelte from "@/interface/main";
|
||||
import { SettingsResizer } from "@/seqta/ui/SettingsResizer";
|
||||
import Settings from "@/interface/pages/settings.svelte";
|
||||
|
||||
export function addExtensionSettings() {
|
||||
const extensionPopup = document.createElement("div")
|
||||
extensionPopup.classList.add("outside-container", "hide")
|
||||
extensionPopup.id = "ExtensionPopup"
|
||||
|
||||
const extensionContainer = document.querySelector(
|
||||
"#container",
|
||||
) as HTMLDivElement
|
||||
if (extensionContainer) extensionContainer.appendChild(extensionPopup)
|
||||
|
||||
// create shadow dom and render svelte app
|
||||
try {
|
||||
const shadow = extensionPopup.attachShadow({ mode: "open" })
|
||||
requestIdleCallback(() => renderSvelte(Settings, shadow))
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
const extensionPopup = document.createElement("div");
|
||||
extensionPopup.classList.add("outside-container", "hide");
|
||||
extensionPopup.id = "ExtensionPopup";
|
||||
|
||||
const extensionContainer = document.querySelector(
|
||||
"#container",
|
||||
) as HTMLDivElement;
|
||||
if (extensionContainer) extensionContainer.appendChild(extensionPopup);
|
||||
|
||||
// create shadow dom and render svelte app
|
||||
try {
|
||||
const shadow = extensionPopup.attachShadow({ mode: "open" });
|
||||
requestIdleCallback(() => renderSvelte(Settings, shadow));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
const container = document.getElementById("container");
|
||||
|
||||
new SettingsResizer();
|
||||
|
||||
container!.onclick = (event) => {
|
||||
if (!SettingsClicked) return;
|
||||
|
||||
if (!(event.target as HTMLElement).closest("#AddedSettings")) {
|
||||
if (event.target == extensionPopup) return;
|
||||
changeSettingsClicked(closeExtensionPopup());
|
||||
}
|
||||
|
||||
const container = document.getElementById("container")
|
||||
|
||||
new SettingsResizer()
|
||||
|
||||
container!.onclick = (event) => {
|
||||
if (!SettingsClicked) return
|
||||
|
||||
if (!(event.target as HTMLElement).closest("#AddedSettings")) {
|
||||
if (event.target == extensionPopup) return
|
||||
changeSettingsClicked(closeExtensionPopup())
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import ShortcutLinks from "@/seqta/content/links.json"
|
||||
import stringToHTML from "../stringToHTML"
|
||||
import ShortcutLinks from "@/seqta/content/links.json";
|
||||
import stringToHTML from "../stringToHTML";
|
||||
|
||||
export function addShortcuts(shortcuts: any) {
|
||||
for (let i = 0; i < shortcuts.length; i++) {
|
||||
const currentShortcut = shortcuts[i]
|
||||
const currentShortcut = shortcuts[i];
|
||||
|
||||
if (currentShortcut?.enabled) {
|
||||
const Itemname = (currentShortcut?.name ?? "").replace(/\s/g, "")
|
||||
const Itemname = (currentShortcut?.name ?? "").replace(/\s/g, "");
|
||||
|
||||
const linkDetails =
|
||||
ShortcutLinks?.[Itemname as keyof typeof ShortcutLinks]
|
||||
ShortcutLinks?.[Itemname as keyof typeof ShortcutLinks];
|
||||
if (linkDetails) {
|
||||
createNewShortcut(
|
||||
linkDetails.link,
|
||||
linkDetails.icon,
|
||||
linkDetails.viewBox,
|
||||
currentShortcut?.name,
|
||||
)
|
||||
);
|
||||
} else {
|
||||
console.warn(`No link details found for '${Itemname}'`)
|
||||
console.warn(`No link details found for '${Itemname}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,21 +26,21 @@ export function addShortcuts(shortcuts: any) {
|
||||
|
||||
function createNewShortcut(link: any, icon: any, viewBox: any, title: any) {
|
||||
// Creates the stucture and element information for each seperate shortcut
|
||||
let shortcut = document.createElement("a")
|
||||
shortcut.setAttribute("href", link)
|
||||
shortcut.setAttribute("target", "_blank")
|
||||
let shortcutdiv = document.createElement("div")
|
||||
shortcutdiv.classList.add("shortcut")
|
||||
let shortcut = document.createElement("a");
|
||||
shortcut.setAttribute("href", link);
|
||||
shortcut.setAttribute("target", "_blank");
|
||||
let shortcutdiv = document.createElement("div");
|
||||
shortcutdiv.classList.add("shortcut");
|
||||
|
||||
let image = stringToHTML(
|
||||
`<svg style="width:39px;height:39px" viewBox="${viewBox}"><path fill="currentColor" d="${icon}" /></svg>`,
|
||||
).firstChild
|
||||
;(image! as HTMLElement).classList.add("shortcuticondiv")
|
||||
let text = document.createElement("p")
|
||||
text.textContent = title
|
||||
shortcutdiv.append(image as HTMLElement)
|
||||
shortcutdiv.append(text)
|
||||
shortcut.append(shortcutdiv)
|
||||
).firstChild;
|
||||
(image! as HTMLElement).classList.add("shortcuticondiv");
|
||||
let text = document.createElement("p");
|
||||
text.textContent = title;
|
||||
shortcutdiv.append(image as HTMLElement);
|
||||
shortcutdiv.append(text);
|
||||
shortcut.append(shortcutdiv);
|
||||
|
||||
document.getElementById("shortcuts")!.appendChild(shortcut)
|
||||
}
|
||||
document.getElementById("shortcuts")!.appendChild(shortcut);
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
||||
import { animate } from "motion"
|
||||
import { animate } from "motion";
|
||||
|
||||
import { settingsPopup } from "@/interface/hooks/SettingsPopup"
|
||||
import { settingsPopup } from "@/interface/hooks/SettingsPopup";
|
||||
|
||||
export let SettingsClicked = false
|
||||
export let SettingsClicked = false;
|
||||
|
||||
export const closeExtensionPopup = (extensionPopup?: HTMLElement) => {
|
||||
if (!extensionPopup)
|
||||
extensionPopup = document.getElementById("ExtensionPopup")!
|
||||
|
||||
extensionPopup.classList.add("hide")
|
||||
if (settingsState.animations) {
|
||||
animate(1, 0, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup.style.opacity = Math.max(0, progress).toString()
|
||||
extensionPopup.style.transform = `scale(${Math.max(0, progress)})`
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 520,
|
||||
damping: 20,
|
||||
})
|
||||
} else {
|
||||
extensionPopup.style.opacity = "0"
|
||||
extensionPopup.style.transform = "scale(0)"
|
||||
}
|
||||
|
||||
settingsPopup.triggerClose()
|
||||
return SettingsClicked = false
|
||||
if (!extensionPopup)
|
||||
extensionPopup = document.getElementById("ExtensionPopup")!;
|
||||
|
||||
extensionPopup.classList.add("hide");
|
||||
if (settingsState.animations) {
|
||||
animate(1, 0, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup.style.opacity = Math.max(0, progress).toString();
|
||||
extensionPopup.style.transform = `scale(${Math.max(0, progress)})`;
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 520,
|
||||
damping: 20,
|
||||
});
|
||||
} else {
|
||||
extensionPopup.style.opacity = "0";
|
||||
extensionPopup.style.transform = "scale(0)";
|
||||
}
|
||||
|
||||
export function changeSettingsClicked(newVal: boolean) {
|
||||
SettingsClicked = newVal
|
||||
}
|
||||
settingsPopup.triggerClose();
|
||||
return (SettingsClicked = false);
|
||||
};
|
||||
|
||||
export function changeSettingsClicked(newVal: boolean) {
|
||||
SettingsClicked = newVal;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import stringToHTML from "../stringToHTML"
|
||||
import stringToHTML from "../stringToHTML";
|
||||
|
||||
export function CreateCustomShortcutDiv(element: any) {
|
||||
// Creates the stucture and element information for each seperate shortcut
|
||||
var shortcut = document.createElement("a")
|
||||
shortcut.setAttribute("href", element.url)
|
||||
shortcut.setAttribute("target", "_blank")
|
||||
var shortcutdiv = document.createElement("div")
|
||||
shortcutdiv.classList.add("shortcut")
|
||||
shortcutdiv.classList.add("customshortcut")
|
||||
var shortcut = document.createElement("a");
|
||||
shortcut.setAttribute("href", element.url);
|
||||
shortcut.setAttribute("target", "_blank");
|
||||
var shortcutdiv = document.createElement("div");
|
||||
shortcutdiv.classList.add("shortcut");
|
||||
shortcutdiv.classList.add("customshortcut");
|
||||
|
||||
let image = stringToHTML(
|
||||
`
|
||||
@@ -25,13 +25,13 @@ export function CreateCustomShortcutDiv(element: any) {
|
||||
</text>
|
||||
</svg>
|
||||
`,
|
||||
).firstChild
|
||||
;(image as HTMLElement).classList.add("shortcuticondiv")
|
||||
var text = document.createElement("p")
|
||||
text.textContent = element.name
|
||||
shortcutdiv.append(image!)
|
||||
shortcutdiv.append(text)
|
||||
shortcut.append(shortcutdiv)
|
||||
).firstChild;
|
||||
(image as HTMLElement).classList.add("shortcuticondiv");
|
||||
var text = document.createElement("p");
|
||||
text.textContent = element.name;
|
||||
shortcutdiv.append(image!);
|
||||
shortcutdiv.append(text);
|
||||
shortcut.append(shortcutdiv);
|
||||
|
||||
document.getElementById("shortcuts")!.append(shortcut)
|
||||
}
|
||||
document.getElementById("shortcuts")!.append(shortcut);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
export function CreateElement(
|
||||
type: string,
|
||||
class_?: any,
|
||||
id?: any,
|
||||
innerText?: string,
|
||||
innerHTML?: string,
|
||||
style?: string,
|
||||
) {
|
||||
let element = document.createElement(type)
|
||||
if (class_ !== undefined) {
|
||||
element.classList.add(class_)
|
||||
}
|
||||
if (id !== undefined) {
|
||||
element.id = id
|
||||
}
|
||||
if (innerText !== undefined) {
|
||||
element.innerText = innerText
|
||||
}
|
||||
if (innerHTML !== undefined) {
|
||||
element.innerHTML = innerHTML
|
||||
}
|
||||
if (style !== undefined) {
|
||||
element.style.cssText = style
|
||||
}
|
||||
return element
|
||||
}
|
||||
type: string,
|
||||
class_?: any,
|
||||
id?: any,
|
||||
innerText?: string,
|
||||
innerHTML?: string,
|
||||
style?: string,
|
||||
) {
|
||||
let element = document.createElement(type);
|
||||
if (class_ !== undefined) {
|
||||
element.classList.add(class_);
|
||||
}
|
||||
if (id !== undefined) {
|
||||
element.id = id;
|
||||
}
|
||||
if (innerText !== undefined) {
|
||||
element.innerText = innerText;
|
||||
}
|
||||
if (innerHTML !== undefined) {
|
||||
element.innerHTML = innerHTML;
|
||||
}
|
||||
if (style !== undefined) {
|
||||
element.style.cssText = style;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
export function RemoveShortcutDiv(elements: any) {
|
||||
if (elements.length === 0) return
|
||||
if (elements.length === 0) return;
|
||||
|
||||
elements.forEach((element: any) => {
|
||||
const shortcuts = document.querySelectorAll(".shortcut")
|
||||
const shortcuts = document.querySelectorAll(".shortcut");
|
||||
shortcuts.forEach((shortcut) => {
|
||||
const anchorElement = shortcut.parentElement // the <a> element is the parent
|
||||
const textElement = shortcut.querySelector("p") // <p> is a direct child of .shortcut
|
||||
const title = textElement ? textElement.textContent : ""
|
||||
const anchorElement = shortcut.parentElement; // the <a> element is the parent
|
||||
const textElement = shortcut.querySelector("p"); // <p> is a direct child of .shortcut
|
||||
const title = textElement ? textElement.textContent : "";
|
||||
|
||||
let shouldRemove = title === element.name
|
||||
let shouldRemove = title === element.name;
|
||||
|
||||
// Check href only if element.url exists
|
||||
if (element.url) {
|
||||
shouldRemove =
|
||||
shouldRemove && anchorElement!.getAttribute("href") === element.url
|
||||
shouldRemove && anchorElement!.getAttribute("href") === element.url;
|
||||
}
|
||||
|
||||
if (shouldRemove) {
|
||||
anchorElement!.remove()
|
||||
anchorElement!.remove();
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,25 +19,25 @@ export async function UploadImage(file: File): Promise<any> {
|
||||
|
||||
// Setting up the request options
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Cookie': cookies,
|
||||
'X-File-Name': fileName
|
||||
Cookie: cookies,
|
||||
"X-File-Name": fileName,
|
||||
},
|
||||
body: file // Binary file data
|
||||
body: file, // Binary file data
|
||||
};
|
||||
|
||||
// Making the fetch request and returning the promise
|
||||
return await fetch('/seqta/student/file/upload/xhr2', requestOptions)
|
||||
.then(async response => {
|
||||
return await fetch("/seqta/student/file/upload/xhr2", requestOptions)
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
const json = await response.json();
|
||||
return `/seqta/student/load/file?type=message&file=${json.uuid}`;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during file upload:', error);
|
||||
.catch((error) => {
|
||||
console.error("Error during file upload:", error);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { CreateElement } from "@/seqta/utils/CreateEnable/CreateElement"
|
||||
import { CreateElement } from "@/seqta/utils/CreateEnable/CreateElement";
|
||||
|
||||
export function FilterUpcomingAssessments(subjectoptions: any) {
|
||||
for (var item in subjectoptions) {
|
||||
let subjectdivs = document.querySelectorAll(`[data-subject="${item}"]`)
|
||||
let subjectdivs = document.querySelectorAll(`[data-subject="${item}"]`);
|
||||
|
||||
for (let i = 0; i < subjectdivs.length; i++) {
|
||||
const element = subjectdivs[i]
|
||||
const element = subjectdivs[i];
|
||||
|
||||
if (!subjectoptions[item]) {
|
||||
element.classList.add("hidden")
|
||||
element.classList.add("hidden");
|
||||
}
|
||||
if (subjectoptions[item]) {
|
||||
element.classList.remove("hidden")
|
||||
element.classList.remove("hidden");
|
||||
}
|
||||
(element.parentNode! as HTMLElement).classList.remove("hidden")
|
||||
(element.parentNode! as HTMLElement).classList.remove("hidden");
|
||||
|
||||
let children = element.parentNode!.parentNode!.children
|
||||
let children = element.parentNode!.parentNode!.children;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const element = children[i]
|
||||
const element = children[i];
|
||||
if (element.hasAttribute("data-hidden")) {
|
||||
element.remove()
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,33 +35,33 @@ export function FilterUpcomingAssessments(subjectoptions: any) {
|
||||
) {
|
||||
(element.parentNode!.parentNode! as HTMLElement).classList.add(
|
||||
"hidden",
|
||||
)
|
||||
);
|
||||
} else {
|
||||
AddPlaceHolderToParent(
|
||||
element.parentNode!.parentNode,
|
||||
element.parentNode!.querySelectorAll(".hidden").length,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(element.parentNode!.parentNode! as HTMLElement).classList.remove(
|
||||
"hidden",
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function AddPlaceHolderToParent(parent: any, numberofassessments: any) {
|
||||
let textcontainer = CreateElement("div", "upcoming-blank")
|
||||
let textblank = CreateElement("p", "upcoming-hiddenassessment")
|
||||
let s = ""
|
||||
let textcontainer = CreateElement("div", "upcoming-blank");
|
||||
let textblank = CreateElement("p", "upcoming-hiddenassessment");
|
||||
let s = "";
|
||||
if (numberofassessments > 1) {
|
||||
s = "s"
|
||||
s = "s";
|
||||
}
|
||||
textblank.innerText = `${numberofassessments} hidden assessment${s} due`
|
||||
textcontainer.append(textblank)
|
||||
textcontainer.setAttribute("data-hidden", "true")
|
||||
textblank.innerText = `${numberofassessments} hidden assessment${s} due`;
|
||||
textcontainer.append(textblank);
|
||||
textcontainer.setAttribute("data-hidden", "true");
|
||||
|
||||
parent.append(textcontainer)
|
||||
}
|
||||
parent.append(textcontainer);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +1,26 @@
|
||||
import stringToHTML from "../stringToHTML"
|
||||
import browser from "webextension-polyfill"
|
||||
import { settingsState } from "../listeners/SettingsState"
|
||||
import { animate, stagger } from "motion"
|
||||
import { DeleteWhatsNew } from "../Whatsnew"
|
||||
import stringToHTML from "../stringToHTML";
|
||||
import browser from "webextension-polyfill";
|
||||
import { settingsState } from "../listeners/SettingsState";
|
||||
import { animate, stagger } from "motion";
|
||||
import { DeleteWhatsNew } from "../Whatsnew";
|
||||
|
||||
export function OpenAboutPage() {
|
||||
const background = document.createElement("div")
|
||||
background.id = "whatsnewbk"
|
||||
background.classList.add("whatsnewBackground")
|
||||
|
||||
const container = document.createElement("div")
|
||||
container.classList.add("whatsnewContainer")
|
||||
|
||||
var header: any = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
const background = document.createElement("div");
|
||||
background.id = "whatsnewbk";
|
||||
background.classList.add("whatsnewBackground");
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("whatsnewContainer");
|
||||
|
||||
var header: any = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
<h1>About</h1>
|
||||
<p>BetterSEQTA+ V${browser.runtime.getManifest().version}</p>
|
||||
</div>`,
|
||||
).firstChild
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
).firstChild;
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
<div class="whatsnewTextContainer" style="overflow-y: scroll;">
|
||||
<img src="${settingsState.DarkMode ? "https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/branding/dark.jpg" : "https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/branding/light.jpg"}" class="aboutImg" />
|
||||
|
||||
@@ -29,9 +29,9 @@ export function OpenAboutPage() {
|
||||
<h1>Credits</h1>
|
||||
<p>Nulkem created the original extension, was ported to Manifest V3 by MEGA-Dawg68, and is under active development by Crazypersonalph and SethBurkart123.</p>
|
||||
</div>
|
||||
`).firstChild
|
||||
|
||||
let footer = stringToHTML(/* html */ `
|
||||
`).firstChild;
|
||||
|
||||
let footer = stringToHTML(/* html */ `
|
||||
<div class="whatsnewFooter">
|
||||
<div>
|
||||
Report bugs and feedback:
|
||||
@@ -52,56 +52,56 @@ export function OpenAboutPage() {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`).firstChild
|
||||
|
||||
let exitbutton = document.createElement("div")
|
||||
exitbutton.id = "whatsnewclosebutton"
|
||||
|
||||
container.append(header)
|
||||
container.append(text as ChildNode)
|
||||
container.append(footer as ChildNode)
|
||||
container.append(exitbutton)
|
||||
|
||||
background.append(container)
|
||||
|
||||
document.getElementById("container")!.append(background)
|
||||
|
||||
let bkelement = document.getElementById("whatsnewbk")
|
||||
let popup = document.getElementsByClassName("whatsnewContainer")[0]
|
||||
|
||||
if (settingsState.animations) {
|
||||
animate(
|
||||
[popup, bkelement as HTMLElement],
|
||||
{ scale: [0, 1] },
|
||||
{
|
||||
type: "spring",
|
||||
stiffness: 220,
|
||||
damping: 18,
|
||||
},
|
||||
)
|
||||
|
||||
animate(
|
||||
".whatsnewTextContainer *",
|
||||
{ opacity: [0, 1], y: [10, 0] },
|
||||
{
|
||||
delay: stagger(0.05, { startDelay: 0.1 }),
|
||||
duration: 0.5,
|
||||
ease: [0.22, 0.03, 0.26, 1],
|
||||
},
|
||||
)
|
||||
`).firstChild;
|
||||
|
||||
let exitbutton = document.createElement("div");
|
||||
exitbutton.id = "whatsnewclosebutton";
|
||||
|
||||
container.append(header);
|
||||
container.append(text as ChildNode);
|
||||
container.append(footer as ChildNode);
|
||||
container.append(exitbutton);
|
||||
|
||||
background.append(container);
|
||||
|
||||
document.getElementById("container")!.append(background);
|
||||
|
||||
let bkelement = document.getElementById("whatsnewbk");
|
||||
let popup = document.getElementsByClassName("whatsnewContainer")[0];
|
||||
|
||||
if (settingsState.animations) {
|
||||
animate(
|
||||
[popup, bkelement as HTMLElement],
|
||||
{ scale: [0, 1] },
|
||||
{
|
||||
type: "spring",
|
||||
stiffness: 220,
|
||||
damping: 18,
|
||||
},
|
||||
);
|
||||
|
||||
animate(
|
||||
".whatsnewTextContainer *",
|
||||
{ opacity: [0, 1], y: [10, 0] },
|
||||
{
|
||||
delay: stagger(0.05, { startDelay: 0.1 }),
|
||||
duration: 0.5,
|
||||
ease: [0.22, 0.03, 0.26, 1],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
delete settingsState.justupdated;
|
||||
|
||||
bkelement!.addEventListener("click", function (event) {
|
||||
// Check if the click event originated from the element itself and not any of its children
|
||||
if (event.target === bkelement) {
|
||||
DeleteWhatsNew();
|
||||
}
|
||||
|
||||
delete settingsState.justupdated
|
||||
|
||||
bkelement!.addEventListener("click", function (event) {
|
||||
// Check if the click event originated from the element itself and not any of its children
|
||||
if (event.target === bkelement) {
|
||||
DeleteWhatsNew()
|
||||
}
|
||||
})
|
||||
|
||||
var closeelement = document.getElementById("whatsnewclosebutton")
|
||||
closeelement!.addEventListener("click", function () {
|
||||
DeleteWhatsNew()
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
var closeelement = document.getElementById("whatsnewclosebutton");
|
||||
closeelement!.addEventListener("click", function () {
|
||||
DeleteWhatsNew();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,259 +1,253 @@
|
||||
import type { SettingsState } from "@/types/storage";
|
||||
import { settingsState } from "../listeners/SettingsState";
|
||||
import stringToHTML from "../stringToHTML";
|
||||
import Sortable from "sortablejs";
|
||||
|
||||
import type { SettingsState } from "@/types/storage"
|
||||
import { settingsState } from "../listeners/SettingsState"
|
||||
import stringToHTML from "../stringToHTML"
|
||||
import Sortable from "sortablejs"
|
||||
|
||||
export let MenuOptionsOpen = false
|
||||
|
||||
export let MenuOptionsOpen = false;
|
||||
|
||||
export function OpenMenuOptions() {
|
||||
var container = document.getElementById("container")
|
||||
var menu = document.getElementById("menu")
|
||||
var container = document.getElementById("container");
|
||||
var menu = document.getElementById("menu");
|
||||
|
||||
if (settingsState.defaultmenuorder.length == 0) {
|
||||
let childnodes = menu!.firstChild!.childNodes
|
||||
let newdefaultmenuorder = []
|
||||
let childnodes = menu!.firstChild!.childNodes;
|
||||
let newdefaultmenuorder = [];
|
||||
for (let i = 0; i < childnodes.length; i++) {
|
||||
const element = childnodes[i]
|
||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key)
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder
|
||||
const element = childnodes[i];
|
||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key);
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder;
|
||||
}
|
||||
}
|
||||
let childnodes = menu!.firstChild!.childNodes
|
||||
let childnodes = menu!.firstChild!.childNodes;
|
||||
if (settingsState.defaultmenuorder.length != childnodes.length) {
|
||||
for (let i = 0; i < childnodes.length; i++) {
|
||||
const element = childnodes[i]
|
||||
const element = childnodes[i];
|
||||
if (
|
||||
!settingsState.defaultmenuorder.indexOf(
|
||||
(element as HTMLElement).dataset.key,
|
||||
)
|
||||
) {
|
||||
let newdefaultmenuorder = settingsState.defaultmenuorder
|
||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key)
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder
|
||||
let newdefaultmenuorder = settingsState.defaultmenuorder;
|
||||
newdefaultmenuorder.push((element as HTMLElement).dataset.key);
|
||||
settingsState.defaultmenuorder = newdefaultmenuorder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MenuOptionsOpen = true
|
||||
MenuOptionsOpen = true;
|
||||
|
||||
var cover = document.createElement("div")
|
||||
cover.classList.add("notMenuCover")
|
||||
menu!.style.zIndex = "20"
|
||||
menu!.style.setProperty("--menuHidden", "flex")
|
||||
container!.append(cover)
|
||||
var cover = document.createElement("div");
|
||||
cover.classList.add("notMenuCover");
|
||||
menu!.style.zIndex = "20";
|
||||
menu!.style.setProperty("--menuHidden", "flex");
|
||||
container!.append(cover);
|
||||
|
||||
var menusettings = document.createElement("div")
|
||||
menusettings.classList.add("editmenuoption-container")
|
||||
var menusettings = document.createElement("div");
|
||||
menusettings.classList.add("editmenuoption-container");
|
||||
|
||||
var defaultbutton = document.createElement("div")
|
||||
defaultbutton.classList.add("editmenuoption")
|
||||
defaultbutton.innerText = "Restore Default"
|
||||
defaultbutton.id = "restoredefaultoption"
|
||||
var defaultbutton = document.createElement("div");
|
||||
defaultbutton.classList.add("editmenuoption");
|
||||
defaultbutton.innerText = "Restore Default";
|
||||
defaultbutton.id = "restoredefaultoption";
|
||||
|
||||
var savebutton = document.createElement("div")
|
||||
savebutton.classList.add("editmenuoption")
|
||||
savebutton.innerText = "Save"
|
||||
savebutton.id = "restoredefaultoption"
|
||||
var savebutton = document.createElement("div");
|
||||
savebutton.classList.add("editmenuoption");
|
||||
savebutton.innerText = "Save";
|
||||
savebutton.id = "restoredefaultoption";
|
||||
|
||||
menusettings.appendChild(defaultbutton)
|
||||
menusettings.appendChild(savebutton)
|
||||
menusettings.appendChild(defaultbutton);
|
||||
menusettings.appendChild(savebutton);
|
||||
|
||||
menu!.appendChild(menusettings)
|
||||
menu!.appendChild(menusettings);
|
||||
|
||||
var ListItems = menu!.firstChild!.childNodes
|
||||
var ListItems = menu!.firstChild!.childNodes;
|
||||
for (let i = 0; i < ListItems.length; i++) {
|
||||
const element1 = ListItems[i]
|
||||
const element = element1 as HTMLElement
|
||||
const element1 = ListItems[i];
|
||||
const element = element1 as HTMLElement;
|
||||
|
||||
;(element as HTMLElement).classList.add("draggable")
|
||||
(element as HTMLElement).classList.add("draggable");
|
||||
if ((element as HTMLElement).classList.contains("hasChildren")) {
|
||||
(element as HTMLElement).classList.remove("active")
|
||||
;(element.firstChild as HTMLElement).classList.remove("noscroll")
|
||||
(element as HTMLElement).classList.remove("active");
|
||||
(element.firstChild as HTMLElement).classList.remove("noscroll");
|
||||
}
|
||||
|
||||
let MenuItemToggle = stringToHTML(
|
||||
`<div class="onoffswitch" style="margin: auto 0;"><input class="onoffswitch-checkbox notification menuitem" type="checkbox" id="${(element as HTMLElement).dataset.key}"><label for="${(element as HTMLElement).dataset.key}" class="onoffswitch-label"></label>`,
|
||||
).firstChild
|
||||
;(element as HTMLElement).append(MenuItemToggle!)
|
||||
).firstChild;
|
||||
(element as HTMLElement).append(MenuItemToggle!);
|
||||
|
||||
if (!element.dataset.betterseqta) {
|
||||
const a = document.createElement("section")
|
||||
a.innerHTML = element.innerHTML
|
||||
cloneAttributes(a, element)
|
||||
menu!.firstChild!.insertBefore(a, element)
|
||||
element.remove()
|
||||
const a = document.createElement("section");
|
||||
a.innerHTML = element.innerHTML;
|
||||
cloneAttributes(a, element);
|
||||
menu!.firstChild!.insertBefore(a, element);
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(settingsState.menuitems).length == 0) {
|
||||
menubuttons = menu!.firstChild!.childNodes
|
||||
let menuItems = {} as any
|
||||
menubuttons = menu!.firstChild!.childNodes;
|
||||
let menuItems = {} as any;
|
||||
for (var i = 0; i < menubuttons.length; i++) {
|
||||
var id = (menubuttons[i] as HTMLElement).dataset.key
|
||||
const element: any = {}
|
||||
element.toggle = true
|
||||
;(menuItems[id as keyof typeof menuItems] as any) = element
|
||||
var id = (menubuttons[i] as HTMLElement).dataset.key;
|
||||
const element: any = {};
|
||||
element.toggle = true;
|
||||
(menuItems[id as keyof typeof menuItems] as any) = element;
|
||||
}
|
||||
settingsState.menuitems = menuItems
|
||||
settingsState.menuitems = menuItems;
|
||||
}
|
||||
|
||||
var menubuttons: any = document.getElementsByClassName("menuitem")
|
||||
var menubuttons: any = document.getElementsByClassName("menuitem");
|
||||
|
||||
let menuItems = settingsState.menuitems as any
|
||||
let buttons = document.getElementsByClassName("menuitem")
|
||||
let menuItems = settingsState.menuitems as any;
|
||||
let buttons = document.getElementsByClassName("menuitem");
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
let id = buttons[i].id as string | undefined
|
||||
let id = buttons[i].id as string | undefined;
|
||||
if (menuItems[id as keyof typeof menuItems]) {
|
||||
(buttons[i] as HTMLInputElement).checked =
|
||||
menuItems[id as keyof typeof menuItems].toggle
|
||||
menuItems[id as keyof typeof menuItems].toggle;
|
||||
} else {
|
||||
(buttons[i] as HTMLInputElement).checked = true
|
||||
(buttons[i] as HTMLInputElement).checked = true;
|
||||
}
|
||||
(buttons[i] as HTMLInputElement).checked = true
|
||||
(buttons[i] as HTMLInputElement).checked = true;
|
||||
}
|
||||
|
||||
try {
|
||||
var el = document.querySelector("#menu > ul")
|
||||
var el = document.querySelector("#menu > ul");
|
||||
var sortable = Sortable.create(el as HTMLElement, {
|
||||
draggable: ".draggable",
|
||||
dataIdAttr: "data-key",
|
||||
animation: 150,
|
||||
easing: "cubic-bezier(.5,0,.5,1)",
|
||||
onEnd: function () {
|
||||
saveNewOrder(sortable)
|
||||
saveNewOrder(sortable);
|
||||
},
|
||||
})
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
function changeDisplayProperty(element: any) {
|
||||
if (!element.checked) {
|
||||
element.parentNode.parentNode.style.display = "var(--menuHidden)"
|
||||
element.parentNode.parentNode.style.display = "var(--menuHidden)";
|
||||
}
|
||||
if (element.checked) {
|
||||
element.parentNode.parentNode.style.setProperty(
|
||||
"display",
|
||||
"flex",
|
||||
"important",
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function StoreMenuSettings() {
|
||||
let menu = document.getElementById("menu")
|
||||
const menuItems: any = {}
|
||||
let menubuttons = menu!.firstChild!.childNodes
|
||||
const button = document.getElementsByClassName("menuitem")
|
||||
let menu = document.getElementById("menu");
|
||||
const menuItems: any = {};
|
||||
let menubuttons = menu!.firstChild!.childNodes;
|
||||
const button = document.getElementsByClassName("menuitem");
|
||||
for (let i = 0; i < menubuttons.length; i++) {
|
||||
const id = (menubuttons[i] as HTMLElement).dataset.key
|
||||
const element: any = {}
|
||||
element.toggle = (button[i] as HTMLInputElement).checked
|
||||
const id = (menubuttons[i] as HTMLElement).dataset.key;
|
||||
const element: any = {};
|
||||
element.toggle = (button[i] as HTMLInputElement).checked;
|
||||
|
||||
menuItems[id as keyof typeof menuItems] = element
|
||||
menuItems[id as keyof typeof menuItems] = element;
|
||||
}
|
||||
settingsState.menuitems = menuItems
|
||||
settingsState.menuitems = menuItems;
|
||||
}
|
||||
|
||||
for (let i = 0; i < menubuttons.length; i++) {
|
||||
const element = menubuttons[i]
|
||||
const element = menubuttons[i];
|
||||
element.addEventListener("change", () => {
|
||||
element.parentElement.parentElement.getAttribute("data-key")
|
||||
StoreMenuSettings()
|
||||
changeDisplayProperty(element)
|
||||
})
|
||||
element.parentElement.parentElement.getAttribute("data-key");
|
||||
StoreMenuSettings();
|
||||
changeDisplayProperty(element);
|
||||
});
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
menusettings?.remove()
|
||||
cover?.remove()
|
||||
MenuOptionsOpen = false
|
||||
menu!.style.setProperty("--menuHidden", "none")
|
||||
menusettings?.remove();
|
||||
cover?.remove();
|
||||
MenuOptionsOpen = false;
|
||||
menu!.style.setProperty("--menuHidden", "none");
|
||||
|
||||
for (let i = 0; i < ListItems.length; i++) {
|
||||
const element1 = ListItems[i]
|
||||
const element = element1 as HTMLElement
|
||||
element.classList.remove("draggable")
|
||||
element.setAttribute("draggable", "false")
|
||||
const element1 = ListItems[i];
|
||||
const element = element1 as HTMLElement;
|
||||
element.classList.remove("draggable");
|
||||
element.setAttribute("draggable", "false");
|
||||
|
||||
if (!element.dataset.betterseqta) {
|
||||
const a = document.createElement("li")
|
||||
a.innerHTML = element.innerHTML
|
||||
cloneAttributes(a, element)
|
||||
menu!.firstChild!.insertBefore(a, element)
|
||||
element.remove()
|
||||
const a = document.createElement("li");
|
||||
a.innerHTML = element.innerHTML;
|
||||
cloneAttributes(a, element);
|
||||
menu!.firstChild!.insertBefore(a, element);
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
let switches = menu!.querySelectorAll(".onoffswitch")
|
||||
let switches = menu!.querySelectorAll(".onoffswitch");
|
||||
for (let i = 0; i < switches.length; i++) {
|
||||
switches[i].remove()
|
||||
switches[i].remove();
|
||||
}
|
||||
}
|
||||
|
||||
cover?.addEventListener("click", closeAll)
|
||||
savebutton?.addEventListener("click", closeAll)
|
||||
cover?.addEventListener("click", closeAll);
|
||||
savebutton?.addEventListener("click", closeAll);
|
||||
|
||||
defaultbutton?.addEventListener("click", function () {
|
||||
const options = settingsState.defaultmenuorder
|
||||
settingsState.menuorder = options
|
||||
const options = settingsState.defaultmenuorder;
|
||||
settingsState.menuorder = options;
|
||||
|
||||
ChangeMenuItemPositions(options)
|
||||
ChangeMenuItemPositions(options);
|
||||
|
||||
for (let i = 0; i < menubuttons.length; i++) {
|
||||
const element = menubuttons[i]
|
||||
element.checked = true
|
||||
const element = menubuttons[i];
|
||||
element.checked = true;
|
||||
element.parentNode.parentNode.style.setProperty(
|
||||
"display",
|
||||
"flex",
|
||||
"important",
|
||||
)
|
||||
);
|
||||
}
|
||||
saveNewOrder(sortable)
|
||||
})
|
||||
saveNewOrder(sortable);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function saveNewOrder(sortable: any) {
|
||||
var order = sortable.toArray()
|
||||
settingsState.menuorder = order
|
||||
var order = sortable.toArray();
|
||||
settingsState.menuorder = order;
|
||||
}
|
||||
|
||||
function cloneAttributes(target: any, source: any) {
|
||||
[...source.attributes].forEach((attr) => {
|
||||
target.setAttribute(attr.nodeName, attr.nodeValue)
|
||||
})
|
||||
target.setAttribute(attr.nodeName, attr.nodeValue);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function ChangeMenuItemPositions(menuorder: SettingsState["menuorder"]) {
|
||||
var menuList = document.querySelector("#menu")!.firstChild!.childNodes
|
||||
var menuList = document.querySelector("#menu")!.firstChild!.childNodes;
|
||||
|
||||
let listorder = []
|
||||
let listorder = [];
|
||||
for (let i = 0; i < menuList.length; i++) {
|
||||
const menu = menuList[i] as HTMLElement
|
||||
const menu = menuList[i] as HTMLElement;
|
||||
|
||||
let a = menuorder.indexOf(menu.dataset.key)
|
||||
let a = menuorder.indexOf(menu.dataset.key);
|
||||
|
||||
listorder.push(a)
|
||||
listorder.push(a);
|
||||
}
|
||||
|
||||
var newArr = []
|
||||
var newArr = [];
|
||||
for (var i = 0; i < listorder.length; i++) {
|
||||
newArr[listorder[i]] = menuList[i]
|
||||
newArr[listorder[i]] = menuList[i];
|
||||
}
|
||||
|
||||
let listItemsDOM = document.getElementById("menu")!.firstChild
|
||||
let listItemsDOM = document.getElementById("menu")!.firstChild;
|
||||
for (let i = 0; i < newArr.length; i++) {
|
||||
const element = newArr[i]
|
||||
const element = newArr[i];
|
||||
if (element) {
|
||||
const elem = element as HTMLElement
|
||||
elem.setAttribute("data-checked", "true")
|
||||
listItemsDOM!.appendChild(element)
|
||||
const elem = element as HTMLElement;
|
||||
elem.setAttribute("data-checked", "true");
|
||||
listItemsDOM!.appendChild(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,26 @@ class ReactFiber {
|
||||
private debug: boolean;
|
||||
private messageIdCounter: number = 0; // Counter for unique message IDs
|
||||
|
||||
constructor(selector: string, options: {
|
||||
debug ? : boolean
|
||||
} = {}) {
|
||||
constructor(
|
||||
selector: string,
|
||||
options: {
|
||||
debug?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
this.selector = selector;
|
||||
this.debug = options.debug || false;
|
||||
}
|
||||
|
||||
static find(selector: string, options: {
|
||||
debug ? : boolean
|
||||
} = {}) {
|
||||
static find(
|
||||
selector: string,
|
||||
options: {
|
||||
debug?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
return new ReactFiber(selector, options);
|
||||
}
|
||||
|
||||
private async sendMessage(action: string, payload: any = {}): Promise < any > {
|
||||
private async sendMessage(action: string, payload: any = {}): Promise<any> {
|
||||
return new Promise((resolve, _) => {
|
||||
const messageId = this.messageIdCounter++;
|
||||
const message = {
|
||||
@@ -29,56 +35,58 @@ class ReactFiber {
|
||||
};
|
||||
|
||||
const listener = (response: any) => {
|
||||
if (response.data?.type === 'reactFiberResponse' && response.data?.messageId === messageId) {
|
||||
if (
|
||||
response.data?.type === "reactFiberResponse" &&
|
||||
response.data?.messageId === messageId
|
||||
) {
|
||||
if (this.debug) {
|
||||
console.log("Content Received Response:", response.data.response);
|
||||
}
|
||||
resolve(response.data.response);
|
||||
window.removeEventListener("message", listener)
|
||||
window.removeEventListener("message", listener);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', listener);
|
||||
window.addEventListener("message", listener);
|
||||
window.postMessage(message, "*");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async getState(key ? : string | string[]): Promise < any > {
|
||||
async getState(key?: string | string[]): Promise<any> {
|
||||
return this.sendMessage("getState", {
|
||||
key
|
||||
key,
|
||||
});
|
||||
}
|
||||
|
||||
async setState(update: any | ((prevState: any) => any)): Promise < ReactFiber > {
|
||||
const updateFnString = typeof update === 'function' ? update.toString() : null;
|
||||
const updateObject = typeof update !== 'function' ? update : null;
|
||||
async setState(update: any | ((prevState: any) => any)): Promise<ReactFiber> {
|
||||
const updateFnString =
|
||||
typeof update === "function" ? update.toString() : null;
|
||||
const updateObject = typeof update !== "function" ? update : null;
|
||||
|
||||
await this.sendMessage("setState", {
|
||||
updateFn: updateFnString,
|
||||
updateObject
|
||||
updateObject,
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
async getProps(propName ? : string): Promise < any > {
|
||||
async getProps(propName?: string): Promise<any> {
|
||||
return this.sendMessage("getProp", {
|
||||
propName
|
||||
propName,
|
||||
});
|
||||
}
|
||||
|
||||
async setProp(propName: string, value: any): Promise < ReactFiber > {
|
||||
async setProp(propName: string, value: any): Promise<ReactFiber> {
|
||||
await this.sendMessage("setProp", {
|
||||
propName,
|
||||
value
|
||||
value,
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
async forceUpdate(): Promise < ReactFiber > {
|
||||
async forceUpdate(): Promise<ReactFiber> {
|
||||
await this.sendMessage("forceUpdate");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export default ReactFiber;
|
||||
export default ReactFiber;
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
import { AppendLoadingSymbol } from "@/seqta/ui/Loading"
|
||||
import stringToHTML from "./stringToHTML"
|
||||
import { delay } from "./delay"
|
||||
import { settingsState } from "./listeners/SettingsState"
|
||||
import browser from "webextension-polyfill"
|
||||
import LogoLightOutline from "@/resources/icons/betterseqta-light-outline.png"
|
||||
import { animate, stagger } from "motion"
|
||||
import { AppendLoadingSymbol } from "@/seqta/ui/Loading";
|
||||
import stringToHTML from "./stringToHTML";
|
||||
import { delay } from "./delay";
|
||||
import { settingsState } from "./listeners/SettingsState";
|
||||
import browser from "webextension-polyfill";
|
||||
import LogoLightOutline from "@/resources/icons/betterseqta-light-outline.png";
|
||||
import { animate, stagger } from "motion";
|
||||
|
||||
export async function SendNewsPage() {
|
||||
console.info("[BetterSEQTA+] Started Loading News Page")
|
||||
document.title = "News ― SEQTA Learn"
|
||||
await delay(100)
|
||||
console.info("[BetterSEQTA+] Started Loading News Page");
|
||||
document.title = "News ― SEQTA Learn";
|
||||
await delay(100);
|
||||
|
||||
const element = document.querySelector("[data-key=news]")
|
||||
element!.classList.add("active")
|
||||
const element = document.querySelector("[data-key=news]");
|
||||
element!.classList.add("active");
|
||||
|
||||
// Remove all current elements in the main div to add new elements
|
||||
const main = document.getElementById("main")
|
||||
main!.innerHTML = ""
|
||||
const main = document.getElementById("main");
|
||||
main!.innerHTML = "";
|
||||
|
||||
const html = stringToHTML(/* html */ `
|
||||
<div class="home-root">
|
||||
<div class="home-container" id="news-container">
|
||||
<h1 class="border">Latest Headlines in ${settingsState.newsSource ? settingsState.newsSource.charAt(0).toUpperCase() + settingsState.newsSource.slice(1) : "Australia"}</h1>
|
||||
</div>
|
||||
</div>`)
|
||||
</div>`);
|
||||
|
||||
main!.append(html.firstChild!)
|
||||
main!.append(html.firstChild!);
|
||||
|
||||
const titlediv = document.getElementById("title")!.firstChild
|
||||
;(titlediv! as HTMLElement).innerText = "News"
|
||||
AppendLoadingSymbol("newsloading", "#news-container")
|
||||
const titlediv = document.getElementById("title")!.firstChild;
|
||||
(titlediv! as HTMLElement).innerText = "News";
|
||||
AppendLoadingSymbol("newsloading", "#news-container");
|
||||
|
||||
const response = (await browser.runtime.sendMessage({
|
||||
type: "sendNews",
|
||||
source: settingsState.newsSource,
|
||||
})) as any
|
||||
const newscontainer = document.querySelector("#news-container")
|
||||
document.getElementById("newsloading")?.remove()
|
||||
})) as any;
|
||||
const newscontainer = document.querySelector("#news-container");
|
||||
document.getElementById("newsloading")?.remove();
|
||||
|
||||
// Create a document fragment to batch DOM operations
|
||||
const fragment = document.createDocumentFragment()
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
// Map over articles to create elements
|
||||
response.news.articles.forEach((article: any) => {
|
||||
const newsarticle = document.createElement("a")
|
||||
newsarticle.classList.add("NewsArticle")
|
||||
newsarticle.href = article.url
|
||||
newsarticle.target = "_blank"
|
||||
const newsarticle = document.createElement("a");
|
||||
newsarticle.classList.add("NewsArticle");
|
||||
newsarticle.href = article.url;
|
||||
newsarticle.target = "_blank";
|
||||
|
||||
const articleimage = document.createElement("div")
|
||||
articleimage.classList.add("articleimage")
|
||||
const articleimage = document.createElement("div");
|
||||
articleimage.classList.add("articleimage");
|
||||
|
||||
if (article.urlToImage == "null" || article.urlToImage == null) {
|
||||
articleimage.style.cssText = `
|
||||
background-image: url(${browser.runtime.getURL(LogoLightOutline)});
|
||||
width: 20%;
|
||||
margin: 0 7.5%;
|
||||
`
|
||||
`;
|
||||
} else {
|
||||
articleimage.style.backgroundImage = `url(${article.urlToImage})`
|
||||
articleimage.style.backgroundImage = `url(${article.urlToImage})`;
|
||||
}
|
||||
|
||||
const articletext = document.createElement("div")
|
||||
articletext.classList.add("ArticleText")
|
||||
const articletext = document.createElement("div");
|
||||
articletext.classList.add("ArticleText");
|
||||
|
||||
const title = document.createElement("a")
|
||||
title.innerText = article.title
|
||||
title.href = article.url
|
||||
title.target = "_blank"
|
||||
const title = document.createElement("a");
|
||||
title.innerText = article.title;
|
||||
title.href = article.url;
|
||||
title.target = "_blank";
|
||||
|
||||
const description = document.createElement("p")
|
||||
const description = document.createElement("p");
|
||||
|
||||
article.description =
|
||||
article.description.length > 400
|
||||
? article.description.substring(0, 400) + "..."
|
||||
: article.description
|
||||
description.innerHTML = article.description
|
||||
: article.description;
|
||||
description.innerHTML = article.description;
|
||||
|
||||
articletext.append(title, description)
|
||||
newsarticle.append(articleimage, articletext)
|
||||
fragment.append(newsarticle)
|
||||
})
|
||||
articletext.append(title, description);
|
||||
newsarticle.append(articleimage, articletext);
|
||||
fragment.append(newsarticle);
|
||||
});
|
||||
|
||||
// Single DOM update to append all articles
|
||||
newscontainer?.append(fragment)
|
||||
newscontainer?.append(fragment);
|
||||
|
||||
if (!settingsState.animations) return
|
||||
if (!settingsState.animations) return;
|
||||
|
||||
const articles = Array.from(document.querySelectorAll(".NewsArticle"))
|
||||
const articles = Array.from(document.querySelectorAll(".NewsArticle"));
|
||||
|
||||
animate(
|
||||
articles.slice(0, 20),
|
||||
@@ -99,5 +99,5 @@ export async function SendNewsPage() {
|
||||
damping: 20,
|
||||
mass: 1,
|
||||
},
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
+101
-101
@@ -1,16 +1,16 @@
|
||||
import { settingsState } from "./listeners/SettingsState"
|
||||
import { animate, stagger } from "motion"
|
||||
import stringToHTML from "./stringToHTML"
|
||||
import browser from "webextension-polyfill"
|
||||
import kofi from "@/resources/kofi.png?base64"
|
||||
import { settingsState } from "./listeners/SettingsState";
|
||||
import { animate, stagger } from "motion";
|
||||
import stringToHTML from "./stringToHTML";
|
||||
import browser from "webextension-polyfill";
|
||||
import kofi from "@/resources/kofi.png?base64";
|
||||
|
||||
export async function DeleteWhatsNew() {
|
||||
const bkelement = document.getElementById("whatsnewbk")
|
||||
const popup = document.getElementsByClassName("whatsnewContainer")[0]
|
||||
const bkelement = document.getElementById("whatsnewbk");
|
||||
const popup = document.getElementsByClassName("whatsnewContainer")[0];
|
||||
|
||||
if (!settingsState.animations) {
|
||||
bkelement?.remove()
|
||||
return
|
||||
bkelement?.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
animate(
|
||||
@@ -18,47 +18,47 @@ export async function DeleteWhatsNew() {
|
||||
{ opacity: [1, 0], scale: [1, 0] },
|
||||
{ ease: [0.22, 0.03, 0.26, 1] },
|
||||
).then(() => {
|
||||
bkelement?.remove()
|
||||
})
|
||||
bkelement?.remove();
|
||||
});
|
||||
}
|
||||
|
||||
export function OpenWhatsNewPopup() {
|
||||
const background = document.createElement("div")
|
||||
background.id = "whatsnewbk"
|
||||
background.classList.add("whatsnewBackground")
|
||||
|
||||
const container = document.createElement("div")
|
||||
container.classList.add("whatsnewContainer")
|
||||
|
||||
var header: any = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
const background = document.createElement("div");
|
||||
background.id = "whatsnewbk";
|
||||
background.classList.add("whatsnewBackground");
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("whatsnewContainer");
|
||||
|
||||
var header: any = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
<h1>What's New</h1>
|
||||
<p>BetterSEQTA+ V${browser.runtime.getManifest().version}</p>
|
||||
</div>`,
|
||||
).firstChild
|
||||
|
||||
let imagecont = document.createElement("div")
|
||||
imagecont.classList.add("whatsnewImgContainer")
|
||||
|
||||
let video = document.createElement("video")
|
||||
let source = document.createElement("source")
|
||||
|
||||
source.setAttribute(
|
||||
"src",
|
||||
"https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/update-video.mp4",
|
||||
)
|
||||
video.autoplay = true
|
||||
video.muted = true
|
||||
video.loop = true
|
||||
video.appendChild(source)
|
||||
video.classList.add("whatsnewImg")
|
||||
imagecont.appendChild(video)
|
||||
|
||||
let textcontainer = document.createElement("div")
|
||||
textcontainer.classList.add("whatsnewTextContainer")
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
).firstChild;
|
||||
|
||||
let imagecont = document.createElement("div");
|
||||
imagecont.classList.add("whatsnewImgContainer");
|
||||
|
||||
let video = document.createElement("video");
|
||||
let source = document.createElement("source");
|
||||
|
||||
source.setAttribute(
|
||||
"src",
|
||||
"https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/update-video.mp4",
|
||||
);
|
||||
video.autoplay = true;
|
||||
video.muted = true;
|
||||
video.loop = true;
|
||||
video.appendChild(source);
|
||||
video.classList.add("whatsnewImg");
|
||||
imagecont.appendChild(video);
|
||||
|
||||
let textcontainer = document.createElement("div");
|
||||
textcontainer.classList.add("whatsnewTextContainer");
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: scroll;">
|
||||
<h1>3.4.6.1 - Hot patch!</h1>
|
||||
<li>Fixed storage not updating and sometimes being replaced with default values</li>
|
||||
@@ -238,9 +238,9 @@ export function OpenWhatsNewPopup() {
|
||||
<h1>Create Custom Shortcuts</h1>
|
||||
<li>Found in the BetterSEQTA+ Settings menu, custom shortcuts can now be created with a name and URL of your choice.</li>
|
||||
</div>
|
||||
`).firstChild
|
||||
|
||||
let footer = stringToHTML(/* html */ `
|
||||
`).firstChild;
|
||||
|
||||
let footer = stringToHTML(/* html */ `
|
||||
<div class="whatsnewFooter">
|
||||
<div>
|
||||
Report bugs and feedback:
|
||||
@@ -267,58 +267,58 @@ export function OpenWhatsNewPopup() {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`).firstChild
|
||||
|
||||
let exitbutton = document.createElement("div")
|
||||
exitbutton.id = "whatsnewclosebutton"
|
||||
|
||||
container.append(header)
|
||||
container.append(imagecont)
|
||||
container.append(textcontainer)
|
||||
container.append(text as ChildNode)
|
||||
container.append(footer as ChildNode)
|
||||
container.append(exitbutton)
|
||||
|
||||
background.append(container)
|
||||
|
||||
document.getElementById("container")!.append(background)
|
||||
|
||||
let bkelement = document.getElementById("whatsnewbk")
|
||||
let popup = document.getElementsByClassName("whatsnewContainer")[0]
|
||||
|
||||
if (settingsState.animations) {
|
||||
animate(
|
||||
[popup, bkelement as HTMLElement],
|
||||
{ scale: [0, 1] },
|
||||
{
|
||||
type: "spring",
|
||||
stiffness: 220,
|
||||
damping: 18,
|
||||
},
|
||||
)
|
||||
|
||||
animate(
|
||||
".whatsnewTextContainer *",
|
||||
{ opacity: [0, 1], y: [10, 0] },
|
||||
{
|
||||
delay: stagger(0.05, { startDelay: 0.1 }),
|
||||
duration: 0.5,
|
||||
ease: [0.22, 0.03, 0.26, 1],
|
||||
},
|
||||
)
|
||||
`).firstChild;
|
||||
|
||||
let exitbutton = document.createElement("div");
|
||||
exitbutton.id = "whatsnewclosebutton";
|
||||
|
||||
container.append(header);
|
||||
container.append(imagecont);
|
||||
container.append(textcontainer);
|
||||
container.append(text as ChildNode);
|
||||
container.append(footer as ChildNode);
|
||||
container.append(exitbutton);
|
||||
|
||||
background.append(container);
|
||||
|
||||
document.getElementById("container")!.append(background);
|
||||
|
||||
let bkelement = document.getElementById("whatsnewbk");
|
||||
let popup = document.getElementsByClassName("whatsnewContainer")[0];
|
||||
|
||||
if (settingsState.animations) {
|
||||
animate(
|
||||
[popup, bkelement as HTMLElement],
|
||||
{ scale: [0, 1] },
|
||||
{
|
||||
type: "spring",
|
||||
stiffness: 220,
|
||||
damping: 18,
|
||||
},
|
||||
);
|
||||
|
||||
animate(
|
||||
".whatsnewTextContainer *",
|
||||
{ opacity: [0, 1], y: [10, 0] },
|
||||
{
|
||||
delay: stagger(0.05, { startDelay: 0.1 }),
|
||||
duration: 0.5,
|
||||
ease: [0.22, 0.03, 0.26, 1],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
delete settingsState.justupdated;
|
||||
|
||||
bkelement!.addEventListener("click", function (event) {
|
||||
// Check if the click event originated from the element itself and not any of its children
|
||||
if (event.target === bkelement) {
|
||||
DeleteWhatsNew();
|
||||
}
|
||||
|
||||
delete settingsState.justupdated
|
||||
|
||||
bkelement!.addEventListener("click", function (event) {
|
||||
// Check if the click event originated from the element itself and not any of its children
|
||||
if (event.target === bkelement) {
|
||||
DeleteWhatsNew()
|
||||
}
|
||||
})
|
||||
|
||||
var closeelement = document.getElementById("whatsnewclosebutton")
|
||||
closeelement!.addEventListener("click", function () {
|
||||
DeleteWhatsNew()
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
var closeelement = document.getElementById("whatsnewclosebutton");
|
||||
closeelement!.addEventListener("click", function () {
|
||||
DeleteWhatsNew();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const base64ToBlob = (base64: string, contentType: string = ''): Blob => {
|
||||
const base64ToBlob = (base64: string, contentType: string = ""): Blob => {
|
||||
const byteCharacters = atob(base64);
|
||||
const byteArrays: Uint8Array[] = [];
|
||||
|
||||
@@ -14,4 +14,4 @@ const base64ToBlob = (base64: string, contentType: string = ''): Blob => {
|
||||
return new Blob(byteArrays, { type: contentType });
|
||||
};
|
||||
|
||||
export default base64ToBlob;
|
||||
export default base64ToBlob;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
export function convertTo12HourFormat(
|
||||
time: string,
|
||||
noMinutes: boolean = false,
|
||||
): string {
|
||||
let [hours, minutes] = time.split(":").map(Number)
|
||||
let period = "AM"
|
||||
|
||||
if (hours >= 12) {
|
||||
period = "PM"
|
||||
if (hours > 12) hours -= 12
|
||||
} else if (hours === 0) {
|
||||
hours = 12
|
||||
}
|
||||
|
||||
let hoursStr = hours.toString()
|
||||
if (hoursStr.length === 2 && hoursStr.startsWith("0")) {
|
||||
hoursStr = hoursStr.substring(1)
|
||||
}
|
||||
|
||||
return `${hoursStr}${noMinutes ? "" : `:${minutes.toString().padStart(2, "0")}`} ${period}`
|
||||
}
|
||||
time: string,
|
||||
noMinutes: boolean = false,
|
||||
): string {
|
||||
let [hours, minutes] = time.split(":").map(Number);
|
||||
let period = "AM";
|
||||
|
||||
if (hours >= 12) {
|
||||
period = "PM";
|
||||
if (hours > 12) hours -= 12;
|
||||
} else if (hours === 0) {
|
||||
hours = 12;
|
||||
}
|
||||
|
||||
let hoursStr = hours.toString();
|
||||
if (hoursStr.length === 2 && hoursStr.startsWith("0")) {
|
||||
hoursStr = hoursStr.substring(1);
|
||||
}
|
||||
|
||||
return `${hoursStr}${noMinutes ? "" : `:${minutes.toString().padStart(2, "0")}`} ${period}`;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
export default function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): (...args: Parameters<T>) => void {
|
||||
export default function debounce<T extends (...args: any[]) => void>(
|
||||
fn: T,
|
||||
delay: number,
|
||||
): (...args: Parameters<T>) => void {
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
return function(this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
return function (this: ThisParameterType<T>, ...args: Parameters<T>) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => fn.apply(this, args), delay);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export function base64toblobURL(base64: string) {
|
||||
// Extract base64 data from the data URI
|
||||
const base64Index = base64.indexOf(',') + 1;
|
||||
const base64Index = base64.indexOf(",") + 1;
|
||||
const imageBase64 = base64.substring(base64Index);
|
||||
|
||||
// Convert base64 to blob
|
||||
@@ -10,10 +10,10 @@ export function base64toblobURL(base64: string) {
|
||||
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||||
}
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
const blob = new Blob([byteArray], { type: 'image/png' });
|
||||
const blob = new Blob([byteArray], { type: "image/png" });
|
||||
|
||||
// Convert blob to blob URL
|
||||
const imageUrl = URL.createObjectURL(blob);
|
||||
|
||||
return imageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
import { waitForElm } from "@/seqta/utils/waitForElm"
|
||||
import { waitForElm } from "@/seqta/utils/waitForElm";
|
||||
import ReactFiber from "../ReactFiber";
|
||||
|
||||
const handleNotificationClick = async (target: HTMLElement) => {
|
||||
const notificationItem = target.closest('[class*="notifications__item___"]') as HTMLElement | null;
|
||||
const notificationItem = target.closest(
|
||||
'[class*="notifications__item___"]',
|
||||
) as HTMLElement | null;
|
||||
if (!notificationItem) return;
|
||||
|
||||
const buttonType = notificationItem.getAttribute('data-type');
|
||||
if (buttonType !== 'message') return;
|
||||
const buttonType = notificationItem.getAttribute("data-type");
|
||||
if (buttonType !== "message") return;
|
||||
|
||||
const notificationList = await ReactFiber.find('[class*="notifications__list___"]').getState();
|
||||
const buttonId = notificationItem.getAttribute('data-id');
|
||||
const notificationList = await ReactFiber.find(
|
||||
'[class*="notifications__list___"]',
|
||||
).getState();
|
||||
const buttonId = notificationItem.getAttribute("data-id");
|
||||
if (!buttonId) return;
|
||||
|
||||
const matchingNotification = notificationList.storeState.notifications.items.find(
|
||||
(item: any) => item.notificationID === parseInt(buttonId)
|
||||
);
|
||||
const matchingNotification =
|
||||
notificationList.storeState.notifications.items.find(
|
||||
(item: any) => item.notificationID === parseInt(buttonId),
|
||||
);
|
||||
|
||||
await waitForElm('[class*="Viewer__Viewer___"] > div', true, 20);
|
||||
|
||||
// Select the specific direct message
|
||||
ReactFiber.find('[class*="Viewer__Viewer___"] > div').setState({ selected: new Set([matchingNotification.message.messageID]) });
|
||||
ReactFiber.find('[class*="Viewer__Viewer___"] > div').setState({
|
||||
selected: new Set([matchingNotification.message.messageID]),
|
||||
});
|
||||
|
||||
// Close the notifications panel
|
||||
const notificationButton = document.querySelector('[class*="notifications__notifications___"] > button') as HTMLButtonElement | null;
|
||||
const notificationButton = document.querySelector(
|
||||
'[class*="notifications__notifications___"] > button',
|
||||
) as HTMLButtonElement | null;
|
||||
notificationButton?.click();
|
||||
};
|
||||
|
||||
@@ -33,10 +42,10 @@ const clickListeners = [
|
||||
},
|
||||
];
|
||||
|
||||
const registerClickListeners = () => {
|
||||
document.addEventListener('click', (e) => {
|
||||
const registerClickListeners = () => {
|
||||
document.addEventListener("click", (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
|
||||
|
||||
clickListeners.forEach(({ selector, handler }) => {
|
||||
if (target.closest(selector)) {
|
||||
handler(target);
|
||||
|
||||
@@ -39,28 +39,37 @@ class EventManager {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public register(event: string, options: EventListenerOptions, callback: (element: Element) => void): { unregister: () => void } {
|
||||
public register(
|
||||
event: string,
|
||||
options: EventListenerOptions,
|
||||
callback: (element: Element) => void,
|
||||
): { unregister: () => void } {
|
||||
const id = this.generateUniqueId();
|
||||
if (!this.listeners.has(event)) {
|
||||
this.listeners.set(event, []);
|
||||
}
|
||||
const unregister = () => this.unregisterById(event, id);
|
||||
this.listeners.get(event)!.push({ id, options, callback, unregister });
|
||||
|
||||
|
||||
this.scanExistingElements(options, callback);
|
||||
|
||||
|
||||
this.startObserving(options.parentElement);
|
||||
return { unregister };
|
||||
}
|
||||
|
||||
private async scanExistingElements(options: EventListenerOptions, callback: (element: Element) => void): Promise<void> {
|
||||
private async scanExistingElements(
|
||||
options: EventListenerOptions,
|
||||
callback: (element: Element) => void,
|
||||
): Promise<void> {
|
||||
const root = options.parentElement || document.documentElement;
|
||||
const elements = Array.from(root.getElementsByTagName('*'));
|
||||
const elements = Array.from(root.getElementsByTagName("*"));
|
||||
elements.unshift(root);
|
||||
|
||||
|
||||
for (let i = 0; i < elements.length; i += this.chunkSize) {
|
||||
const chunk = elements.slice(i, i + this.chunkSize);
|
||||
const filteredChunk = chunk.filter(element => this.matchesOptions(element, options));
|
||||
const filteredChunk = chunk.filter((element) =>
|
||||
this.matchesOptions(element, options),
|
||||
);
|
||||
for (const element of filteredChunk) {
|
||||
callback(element);
|
||||
}
|
||||
@@ -76,7 +85,10 @@ class EventManager {
|
||||
private unregisterById(event: string, id: string): void {
|
||||
if (this.listeners.has(event)) {
|
||||
const listeners = this.listeners.get(event)!;
|
||||
this.listeners.set(event, listeners.filter(listener => listener.id !== id));
|
||||
this.listeners.set(
|
||||
event,
|
||||
listeners.filter((listener) => listener.id !== id),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,9 +105,9 @@ class EventManager {
|
||||
}
|
||||
|
||||
private handleMutations(mutations: MutationRecord[]): void {
|
||||
mutations.forEach(mutation => {
|
||||
if (mutation.type === 'childList') {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.type === "childList") {
|
||||
mutation.addedNodes.forEach((node) => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
this.pendingElements.add(node as Element);
|
||||
}
|
||||
@@ -148,19 +160,29 @@ class EventManager {
|
||||
}
|
||||
}
|
||||
|
||||
private matchesOptions(element: Element, options: EventListenerOptions): boolean {
|
||||
if (options.elementType && element.tagName.toLowerCase() !== options.elementType.toLowerCase()) return false;
|
||||
if (options.textContent && element.textContent !== options.textContent) return false;
|
||||
if (options.className && !element.classList.contains(options.className)) return false;
|
||||
private matchesOptions(
|
||||
element: Element,
|
||||
options: EventListenerOptions,
|
||||
): boolean {
|
||||
if (
|
||||
options.elementType &&
|
||||
element.tagName.toLowerCase() !== options.elementType.toLowerCase()
|
||||
)
|
||||
return false;
|
||||
if (options.textContent && element.textContent !== options.textContent)
|
||||
return false;
|
||||
if (options.className && !element.classList.contains(options.className))
|
||||
return false;
|
||||
if (options.id && element.id !== options.id) return false;
|
||||
if (options.customCheck && !options.customCheck(element)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private generateUniqueId(): string {
|
||||
return '_' + Math.random().toString(36).substr(2, 9);
|
||||
return "_" + Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
}
|
||||
|
||||
export const eventManager = EventManager.getInstance();
|
||||
export const initializeEventManager = async () => await EventManager.initialize();
|
||||
export const initializeEventManager = async () =>
|
||||
await EventManager.initialize();
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import browser from 'webextension-polyfill'
|
||||
import browser from "webextension-polyfill";
|
||||
|
||||
import { closeExtensionPopup } from "@/seqta/utils/Closers/closeExtensionPopup"
|
||||
import { MenuOptionsOpen, OpenMenuOptions } from "@/seqta/utils/Openers/OpenMenuOptions"
|
||||
import { closeExtensionPopup } from "@/seqta/utils/Closers/closeExtensionPopup";
|
||||
import {
|
||||
MenuOptionsOpen,
|
||||
OpenMenuOptions,
|
||||
} from "@/seqta/utils/Openers/OpenMenuOptions";
|
||||
|
||||
import { CloseThemeCreator, OpenThemeCreator } from '@/plugins/built-in/themes/ThemeCreator';
|
||||
import sendThemeUpdate from '@/seqta/utils/sendThemeUpdate';
|
||||
import hideSensitiveContent from '@/seqta/ui/dev/hideSensitiveContent';
|
||||
import { ThemeManager } from '@/plugins/built-in/themes/theme-manager';
|
||||
import {
|
||||
CloseThemeCreator,
|
||||
OpenThemeCreator,
|
||||
} from "@/plugins/built-in/themes/ThemeCreator";
|
||||
import sendThemeUpdate from "@/seqta/utils/sendThemeUpdate";
|
||||
import hideSensitiveContent from "@/seqta/ui/dev/hideSensitiveContent";
|
||||
import { ThemeManager } from "@/plugins/built-in/themes/theme-manager";
|
||||
|
||||
const themeManager = ThemeManager.getInstance();
|
||||
|
||||
@@ -16,93 +22,93 @@ export class MessageHandler {
|
||||
browser.runtime.onMessage.addListener(this.routeMessage.bind(this));
|
||||
}
|
||||
routeMessage(request: any, _sender: any, sendResponse: any) {
|
||||
console.debug('Message received:', request)
|
||||
|
||||
console.debug("Message received:", request);
|
||||
|
||||
switch (request.info) {
|
||||
case 'EditSidebar':
|
||||
case "EditSidebar":
|
||||
this.editSidebar();
|
||||
closeExtensionPopup();
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
break;
|
||||
|
||||
case 'UpdateThemePreview':
|
||||
|
||||
case "UpdateThemePreview":
|
||||
if (request?.save == true) {
|
||||
const save = async () => {
|
||||
await themeManager.saveTheme(request.body)
|
||||
await themeManager.saveTheme(request.body);
|
||||
if (request.body.enableTheme) {
|
||||
await themeManager.setTheme(request.body.id)
|
||||
await themeManager.setTheme(request.body.id);
|
||||
}
|
||||
sendResponse({ status: 'success' })
|
||||
sendThemeUpdate()
|
||||
}
|
||||
save()
|
||||
sendResponse({ status: "success" });
|
||||
sendThemeUpdate();
|
||||
};
|
||||
save();
|
||||
} else {
|
||||
themeManager.updatePreview(request.body);
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
}
|
||||
return true;
|
||||
|
||||
case 'GetTheme':
|
||||
|
||||
case "GetTheme":
|
||||
themeManager.getTheme(request.body.themeID).then((theme) => {
|
||||
sendResponse(theme);
|
||||
});
|
||||
return true;
|
||||
|
||||
case 'SetTheme':
|
||||
|
||||
case "SetTheme":
|
||||
themeManager.setTheme(request.body.themeID).then(() => {
|
||||
sendResponse({ status: 'success' });
|
||||
});
|
||||
break;
|
||||
|
||||
case 'DisableTheme':
|
||||
themeManager.disableTheme().then(() => {
|
||||
sendResponse({ status: 'success' });
|
||||
});
|
||||
break;
|
||||
|
||||
case 'DeleteTheme':
|
||||
themeManager.deleteTheme(request.body.themeID).then(() => {
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
});
|
||||
break;
|
||||
|
||||
case 'ListThemes':
|
||||
case "DisableTheme":
|
||||
themeManager.disableTheme().then(() => {
|
||||
sendResponse({ status: "success" });
|
||||
});
|
||||
break;
|
||||
|
||||
case "DeleteTheme":
|
||||
themeManager.deleteTheme(request.body.themeID).then(() => {
|
||||
sendResponse({ status: "success" });
|
||||
});
|
||||
break;
|
||||
|
||||
case "ListThemes":
|
||||
themeManager.getAvailableThemes().then((themes) => {
|
||||
sendResponse(themes);
|
||||
});
|
||||
return true;
|
||||
|
||||
case 'OpenThemeCreator':
|
||||
case "OpenThemeCreator":
|
||||
const themeID = request?.body?.themeID;
|
||||
OpenThemeCreator( themeID ? themeID : '' );
|
||||
OpenThemeCreator(themeID ? themeID : "");
|
||||
closeExtensionPopup();
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
break;
|
||||
|
||||
case 'ShareTheme':
|
||||
|
||||
case "ShareTheme":
|
||||
themeManager.shareTheme(request.body.themeID).then((id) => {
|
||||
sendResponse({ status: 'success', id });
|
||||
sendResponse({ status: "success", id });
|
||||
});
|
||||
return true;
|
||||
|
||||
case 'CloseThemeCreator':
|
||||
case "CloseThemeCreator":
|
||||
try {
|
||||
CloseThemeCreator();
|
||||
} catch (error) {
|
||||
console.error('Error closing theme creator:', error);
|
||||
sendResponse({ status: 'error' });
|
||||
console.error("Error closing theme creator:", error);
|
||||
sendResponse({ status: "error" });
|
||||
}
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
break;
|
||||
|
||||
case 'HideSensitive':
|
||||
case "HideSensitive":
|
||||
hideSensitiveContent();
|
||||
sendResponse({ status: 'success' });
|
||||
sendResponse({ status: "success" });
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
console.debug('Unknown request info:', request.info);
|
||||
}
|
||||
console.debug("Unknown request info:", request.info);
|
||||
}
|
||||
}
|
||||
|
||||
editSidebar() {
|
||||
@@ -110,4 +116,4 @@ export class MessageHandler {
|
||||
OpenMenuOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import browser from 'webextension-polyfill';
|
||||
import type { SettingsState } from '@/types/storage';
|
||||
import type { Subscriber, Unsubscriber } from 'svelte/store';
|
||||
import browser from "webextension-polyfill";
|
||||
import type { SettingsState } from "@/types/storage";
|
||||
import type { Subscriber, Unsubscriber } from "svelte/store";
|
||||
|
||||
type ChangeListener = (newValue: any, oldValue: any) => void;
|
||||
type GlobalChangeListener = (newValue: any, oldValue: any, key: string) => void;
|
||||
@@ -19,7 +19,7 @@ class StorageManager {
|
||||
this.loadFromStorage();
|
||||
|
||||
const handler: ProxyHandler<StorageManager> = {
|
||||
get: (target, prop: keyof SettingsState | 'register' | 'initialize') => {
|
||||
get: (target, prop: keyof SettingsState | "register" | "initialize") => {
|
||||
if (prop in target) {
|
||||
return (target as any)[prop];
|
||||
}
|
||||
@@ -42,7 +42,7 @@ class StorageManager {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
this.initStorageListener();
|
||||
@@ -63,7 +63,10 @@ class StorageManager {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public setKey<K extends keyof SettingsState>(key: K, value: SettingsState[K]): void {
|
||||
public setKey<K extends keyof SettingsState>(
|
||||
key: K,
|
||||
value: SettingsState[K],
|
||||
): void {
|
||||
this.data[key] = value;
|
||||
this.saveToStorage();
|
||||
}
|
||||
@@ -87,7 +90,7 @@ class StorageManager {
|
||||
|
||||
private initStorageListener(): void {
|
||||
browser.storage.onChanged.addListener((changes, areaName) => {
|
||||
if (areaName === 'local') {
|
||||
if (areaName === "local") {
|
||||
for (const [key, { oldValue, newValue }] of Object.entries(changes)) {
|
||||
if (newValue !== undefined) {
|
||||
(this.data as any)[key] = newValue;
|
||||
@@ -151,4 +154,5 @@ class StorageManager {
|
||||
}
|
||||
|
||||
export const settingsState = StorageManager.getInstance();
|
||||
export const initializeSettingsState = async () => await StorageManager.initialize();
|
||||
export const initializeSettingsState = async () =>
|
||||
await StorageManager.initialize();
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { settingsState } from './SettingsState';
|
||||
import { updateAllColors } from '@/seqta/ui/colors/Manager';
|
||||
|
||||
import { settingsState } from "./SettingsState";
|
||||
import { updateAllColors } from "@/seqta/ui/colors/Manager";
|
||||
|
||||
import { addShortcuts } from "@/seqta/utils/Adders/AddShortcuts";
|
||||
import { CreateCustomShortcutDiv } from "@/seqta/utils/CreateEnable/CreateCustomShortcutDiv";
|
||||
import { FilterUpcomingAssessments } from "@/seqta/utils/FilterUpcomingAssessments";
|
||||
import { RemoveShortcutDiv } from "@/seqta/utils/DisableRemove/RemoveShortcutDiv";
|
||||
|
||||
|
||||
import browser from 'webextension-polyfill';
|
||||
import type { CustomShortcut } from '@/types/storage';
|
||||
import browser from "webextension-polyfill";
|
||||
import type { CustomShortcut } from "@/types/storage";
|
||||
|
||||
export class StorageChangeHandler {
|
||||
constructor() {
|
||||
@@ -17,13 +15,22 @@ export class StorageChangeHandler {
|
||||
}
|
||||
|
||||
private registerHandlers() {
|
||||
settingsState.register('selectedColor', updateAllColors.bind(this));
|
||||
settingsState.register('DarkMode', this.handleDarkModeChange.bind(this));
|
||||
settingsState.register('onoff', this.handleOnOffChange.bind(this));
|
||||
settingsState.register('shortcuts', this.handleShortcutsChange.bind(this));
|
||||
settingsState.register('customshortcuts', this.handleCustomShortcutsChange.bind(this));
|
||||
settingsState.register('transparencyEffects', this.handleTransparencyEffectsChange.bind(this));
|
||||
settingsState.register('subjectfilters', FilterUpcomingAssessments.bind(this));
|
||||
settingsState.register("selectedColor", updateAllColors.bind(this));
|
||||
settingsState.register("DarkMode", this.handleDarkModeChange.bind(this));
|
||||
settingsState.register("onoff", this.handleOnOffChange.bind(this));
|
||||
settingsState.register("shortcuts", this.handleShortcutsChange.bind(this));
|
||||
settingsState.register(
|
||||
"customshortcuts",
|
||||
this.handleCustomShortcutsChange.bind(this),
|
||||
);
|
||||
settingsState.register(
|
||||
"transparencyEffects",
|
||||
this.handleTransparencyEffectsChange.bind(this),
|
||||
);
|
||||
settingsState.register(
|
||||
"subjectfilters",
|
||||
FilterUpcomingAssessments.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
private handleDarkModeChange() {
|
||||
@@ -32,16 +39,23 @@ export class StorageChangeHandler {
|
||||
|
||||
private handleOnOffChange(newValue: boolean) {
|
||||
if (newValue) return;
|
||||
browser.runtime.sendMessage({ type: 'reloadTabs' });
|
||||
browser.runtime.sendMessage({ type: "reloadTabs" });
|
||||
}
|
||||
|
||||
private handleCustomShortcutsChange(newValue: CustomShortcut[], oldValue: CustomShortcut[]) {
|
||||
private handleCustomShortcutsChange(
|
||||
newValue: CustomShortcut[],
|
||||
oldValue: CustomShortcut[],
|
||||
) {
|
||||
if (newValue) {
|
||||
if (newValue.length > oldValue.length) {
|
||||
CreateCustomShortcutDiv(newValue[oldValue.length]);
|
||||
} else if (newValue.length < oldValue.length) {
|
||||
const removedElement = oldValue.find(
|
||||
(oldItem: any) => !newValue.some((newItem: any) => JSON.stringify(oldItem) === JSON.stringify(newItem))
|
||||
(oldItem: any) =>
|
||||
!newValue.some(
|
||||
(newItem: any) =>
|
||||
JSON.stringify(oldItem) === JSON.stringify(newItem),
|
||||
),
|
||||
);
|
||||
|
||||
if (removedElement) {
|
||||
@@ -51,7 +65,10 @@ export class StorageChangeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private handleShortcutsChange(newValue: { enabled: boolean, name: string }[], oldValue: { enabled: boolean, name: string }[]) {
|
||||
private handleShortcutsChange(
|
||||
newValue: { enabled: boolean; name: string }[],
|
||||
oldValue: { enabled: boolean; name: string }[],
|
||||
) {
|
||||
const addedShortcuts = newValue.filter((newItem: any) => {
|
||||
const isAdded = oldValue.some((oldItem: any) => {
|
||||
const match = oldItem.name === newItem.name;
|
||||
@@ -80,9 +97,9 @@ export class StorageChangeHandler {
|
||||
|
||||
private handleTransparencyEffectsChange(newValue: boolean) {
|
||||
if (newValue) {
|
||||
document.documentElement.classList.add('transparencyEffects');
|
||||
document.documentElement.classList.add("transparencyEffects");
|
||||
} else {
|
||||
document.documentElement.classList.remove('transparencyEffects');
|
||||
document.documentElement.classList.remove("transparencyEffects");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
<body>
|
||||
<script type="module" src="./migration-iframe.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
interface Data {
|
||||
id: string;
|
||||
blob: Blob;
|
||||
type: 'image' | 'video';
|
||||
type: "image" | "video";
|
||||
}
|
||||
|
||||
const openDB = (): Promise<IDBDatabase> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open('MyDatabase', 1);
|
||||
const request = indexedDB.open("MyDatabase", 1);
|
||||
request.onerror = () => reject(request.error);
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
});
|
||||
@@ -18,7 +18,7 @@ const blobToBase64 = (blob: Blob): Promise<string> => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
const base64 = reader.result as string;
|
||||
resolve(base64.split(',')[1]); // Remove data URL prefix
|
||||
resolve(base64.split(",")[1]); // Remove data URL prefix
|
||||
};
|
||||
reader.onerror = () => reject(reader.error);
|
||||
reader.readAsDataURL(blob);
|
||||
@@ -27,8 +27,8 @@ const blobToBase64 = (blob: Blob): Promise<string> => {
|
||||
|
||||
const getAllBackgrounds = async (): Promise<Data[]> => {
|
||||
const db = await openDB();
|
||||
const tx = db.transaction('backgrounds', 'readonly');
|
||||
const store = tx.objectStore('backgrounds');
|
||||
const tx = db.transaction("backgrounds", "readonly");
|
||||
const store = tx.objectStore("backgrounds");
|
||||
const request = store.getAll();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -38,88 +38,100 @@ const getAllBackgrounds = async (): Promise<Data[]> => {
|
||||
};
|
||||
|
||||
const getSelectedBackground = (): string | null => {
|
||||
return localStorage.getItem('selectedBackground');
|
||||
return localStorage.getItem("selectedBackground");
|
||||
};
|
||||
|
||||
const startMigration = async () => {
|
||||
try {
|
||||
console.info('Starting background extraction...');
|
||||
console.info("Starting background extraction...");
|
||||
let backgrounds: Data[];
|
||||
try {
|
||||
backgrounds = await getAllBackgrounds();
|
||||
if (!backgrounds || backgrounds.length === 0) {
|
||||
console.info('No backgrounds to migrate');
|
||||
window.parent.postMessage({ type: 'MIGRATION_COMPLETE' }, '*');
|
||||
console.info("No backgrounds to migrate");
|
||||
window.parent.postMessage({ type: "MIGRATION_COMPLETE" }, "*");
|
||||
return;
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.name === 'NotFoundError' && error.message.includes('object stores was not found')) {
|
||||
console.info('No backgrounds to migrate: object store not found');
|
||||
window.parent.postMessage({ type: 'MIGRATION_COMPLETE' }, '*');
|
||||
if (
|
||||
error.name === "NotFoundError" &&
|
||||
error.message.includes("object stores was not found")
|
||||
) {
|
||||
console.info("No backgrounds to migrate: object store not found");
|
||||
window.parent.postMessage({ type: "MIGRATION_COMPLETE" }, "*");
|
||||
return;
|
||||
}
|
||||
console.error('Error fetching backgrounds:', error);
|
||||
throw new Error('Failed to fetch backgrounds');
|
||||
console.error("Error fetching backgrounds:", error);
|
||||
throw new Error("Failed to fetch backgrounds");
|
||||
}
|
||||
const selectedBackground = getSelectedBackground();
|
||||
console.info(`Found ${backgrounds.length} backgrounds`);
|
||||
|
||||
window.parent.postMessage({ type: 'GET_LAST_PROCESSED_ID' }, '*');
|
||||
window.parent.postMessage({ type: "GET_LAST_PROCESSED_ID" }, "*");
|
||||
|
||||
const lastProcessedId = await new Promise<string | null>(resolve => {
|
||||
const lastProcessedId = await new Promise<string | null>((resolve) => {
|
||||
const handler = (event: MessageEvent) => {
|
||||
if (event.data.type === 'LAST_PROCESSED_ID') {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.type === "LAST_PROCESSED_ID") {
|
||||
window.removeEventListener("message", handler);
|
||||
resolve(event.data.id);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.addEventListener("message", handler);
|
||||
});
|
||||
|
||||
const remainingBackgrounds = lastProcessedId
|
||||
? backgrounds.slice(backgrounds.findIndex(b => b.id === lastProcessedId) + 1)
|
||||
const remainingBackgrounds = lastProcessedId
|
||||
? backgrounds.slice(
|
||||
backgrounds.findIndex((b) => b.id === lastProcessedId) + 1,
|
||||
)
|
||||
: backgrounds;
|
||||
|
||||
console.info(`Processing ${remainingBackgrounds.length} remaining backgrounds`);
|
||||
console.info(
|
||||
`Processing ${remainingBackgrounds.length} remaining backgrounds`,
|
||||
);
|
||||
|
||||
for (let i = 0; i < remainingBackgrounds.length; i++) {
|
||||
const background = remainingBackgrounds[i];
|
||||
const base64Data = await blobToBase64(background.blob);
|
||||
|
||||
window.parent.postMessage({
|
||||
type: 'BACKGROUND_DATA',
|
||||
payload: {
|
||||
id: background.id,
|
||||
data: base64Data,
|
||||
mediaType: background.type,
|
||||
total: backgrounds.length,
|
||||
processed: i + 1,
|
||||
isSelected: background.id === selectedBackground
|
||||
}
|
||||
}, '*');
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: "BACKGROUND_DATA",
|
||||
payload: {
|
||||
id: background.id,
|
||||
data: base64Data,
|
||||
mediaType: background.type,
|
||||
total: backgrounds.length,
|
||||
processed: i + 1,
|
||||
isSelected: background.id === selectedBackground,
|
||||
},
|
||||
},
|
||||
"*",
|
||||
);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
window.parent.postMessage({ type: 'MIGRATION_COMPLETE' }, '*');
|
||||
|
||||
window.parent.postMessage({ type: "MIGRATION_COMPLETE" }, "*");
|
||||
} catch (error: any) {
|
||||
console.error('Extraction failed:', error);
|
||||
window.parent.postMessage({
|
||||
type: 'MIGRATION_ERROR',
|
||||
error: error.message || 'Unknown error'
|
||||
}, '*');
|
||||
console.error("Extraction failed:", error);
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: "MIGRATION_ERROR",
|
||||
error: error.message || "Unknown error",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
window.addEventListener("message", (event) => {
|
||||
switch (event.data.type) {
|
||||
case 'PING':
|
||||
window.parent.postMessage({ type: 'PONG' }, '*');
|
||||
case "PING":
|
||||
window.parent.postMessage({ type: "PONG" }, "*");
|
||||
break;
|
||||
|
||||
case 'START_MIGRATION':
|
||||
|
||||
case "START_MIGRATION":
|
||||
startMigration();
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,6 @@ export class Mutex {
|
||||
|
||||
this.mutex = this.mutex.then(() => new Promise(begin));
|
||||
|
||||
return new Promise(res => begin = res);
|
||||
return new Promise((res) => (begin = res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ export default function sendThemeUpdate() {
|
||||
if (iframe) {
|
||||
iframe.contentWindow?.postMessage({ type: 'themeChanged' }, '*');
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,37 @@
|
||||
import { changeSettingsClicked, closeExtensionPopup, SettingsClicked } from "./Closers/closeExtensionPopup"
|
||||
import { animate } from "motion"
|
||||
import { settingsState } from "./listeners/SettingsState"
|
||||
import {
|
||||
changeSettingsClicked,
|
||||
closeExtensionPopup,
|
||||
SettingsClicked,
|
||||
} from "./Closers/closeExtensionPopup";
|
||||
import { animate } from "motion";
|
||||
import { settingsState } from "./listeners/SettingsState";
|
||||
|
||||
export function setupSettingsButton() {
|
||||
var AddedSettings = document.getElementById("AddedSettings")
|
||||
var extensionPopup = document.getElementById("ExtensionPopup")
|
||||
|
||||
AddedSettings!.addEventListener("click", async () => {
|
||||
if (SettingsClicked) {
|
||||
closeExtensionPopup(extensionPopup as HTMLElement)
|
||||
var AddedSettings = document.getElementById("AddedSettings");
|
||||
var extensionPopup = document.getElementById("ExtensionPopup");
|
||||
|
||||
AddedSettings!.addEventListener("click", async () => {
|
||||
if (SettingsClicked) {
|
||||
closeExtensionPopup(extensionPopup as HTMLElement);
|
||||
} else {
|
||||
if (settingsState.animations) {
|
||||
animate(0, 1, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup!.style.opacity = progress.toString();
|
||||
extensionPopup!.style.transform = `scale(${progress})`;
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 280,
|
||||
damping: 20,
|
||||
});
|
||||
} else {
|
||||
if (settingsState.animations) {
|
||||
animate(0, 1, {
|
||||
onUpdate: (progress) => {
|
||||
extensionPopup!.style.opacity = progress.toString()
|
||||
extensionPopup!.style.transform = `scale(${progress})`
|
||||
},
|
||||
type: "spring",
|
||||
stiffness: 280,
|
||||
damping: 20,
|
||||
})
|
||||
} else {
|
||||
extensionPopup!.style.opacity = "1"
|
||||
extensionPopup!.style.transform = "scale(1)"
|
||||
extensionPopup!.style.transition =
|
||||
"opacity 0s linear, transform 0s linear"
|
||||
}
|
||||
extensionPopup!.classList.remove("hide")
|
||||
changeSettingsClicked(true)
|
||||
extensionPopup!.style.opacity = "1";
|
||||
extensionPopup!.style.transform = "scale(1)";
|
||||
extensionPopup!.style.transition =
|
||||
"opacity 0s linear, transform 0s linear";
|
||||
}
|
||||
})
|
||||
}
|
||||
extensionPopup!.classList.remove("hide");
|
||||
changeSettingsClicked(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import DOMPurify from 'dompurify';
|
||||
import DOMPurify from "dompurify";
|
||||
|
||||
export default function stringToHTML(str: string, styles = false) {
|
||||
const parser = new DOMParser();
|
||||
|
||||
|
||||
str = DOMPurify.sanitize(str, {
|
||||
ADD_ATTR: ['onclick'],
|
||||
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|chrome-extension):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i
|
||||
ADD_ATTR: ["onclick"],
|
||||
ALLOWED_URI_REGEXP:
|
||||
/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|chrome-extension):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
|
||||
});
|
||||
|
||||
const doc = parser.parseFromString(str, 'text/html');
|
||||
const doc = parser.parseFromString(str, "text/html");
|
||||
|
||||
if (styles) {
|
||||
doc.body.style.cssText =
|
||||
'height: auto; overflow: scroll; margin: 0px; background: var(--background-primary);';
|
||||
"height: auto; overflow: scroll; margin: 0px; background: var(--background-primary);";
|
||||
}
|
||||
|
||||
return doc.body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +1,75 @@
|
||||
import { eventManager } from "@/seqta/utils/listeners/EventManager"
|
||||
import { delay } from "@/seqta/utils/delay"
|
||||
import { eventManager } from "@/seqta/utils/listeners/EventManager";
|
||||
import { delay } from "@/seqta/utils/delay";
|
||||
|
||||
export async function waitForElm(
|
||||
selector: string,
|
||||
usePolling: boolean = false,
|
||||
interval: number = 100,
|
||||
maxIterations?: number
|
||||
): Promise<Element> {
|
||||
if (usePolling) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let iterations = 0;
|
||||
if (maxIterations) {
|
||||
iterations = 0;
|
||||
}
|
||||
const checkForElement = () => {
|
||||
const element = document.querySelector(selector)
|
||||
if (element) {
|
||||
resolve(element)
|
||||
} else {
|
||||
if (maxIterations) {
|
||||
iterations++;
|
||||
if (iterations >= maxIterations) {
|
||||
reject(new Error("Element not found"));
|
||||
}
|
||||
}
|
||||
setTimeout(checkForElement, interval)
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", checkForElement)
|
||||
} else {
|
||||
checkForElement()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return new Promise((resolve) => {
|
||||
const registerObserver = () => {
|
||||
const { unregister } = eventManager.register(
|
||||
`${selector}`,
|
||||
{
|
||||
customCheck: (element) => element.matches(selector),
|
||||
},
|
||||
async (element) => {
|
||||
resolve(element)
|
||||
await delay(1)
|
||||
unregister() // Remove the listener once the element is found
|
||||
},
|
||||
)
|
||||
return unregister
|
||||
}
|
||||
|
||||
let unregister = null
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
// DOM is still loading, wait for it to be ready
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
unregister = registerObserver()
|
||||
})
|
||||
} else {
|
||||
unregister = registerObserver()
|
||||
}
|
||||
|
||||
const querySelector = () => document.querySelector(selector)
|
||||
const element = querySelector()
|
||||
|
||||
selector: string,
|
||||
usePolling: boolean = false,
|
||||
interval: number = 100,
|
||||
maxIterations?: number,
|
||||
): Promise<Element> {
|
||||
if (usePolling) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let iterations = 0;
|
||||
if (maxIterations) {
|
||||
iterations = 0;
|
||||
}
|
||||
const checkForElement = () => {
|
||||
const element = document.querySelector(selector);
|
||||
if (element) {
|
||||
if (unregister) unregister()
|
||||
resolve(element)
|
||||
return
|
||||
resolve(element);
|
||||
} else {
|
||||
if (maxIterations) {
|
||||
iterations++;
|
||||
if (iterations >= maxIterations) {
|
||||
reject(new Error("Element not found"));
|
||||
}
|
||||
}
|
||||
setTimeout(checkForElement, interval);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", checkForElement);
|
||||
} else {
|
||||
checkForElement();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return new Promise((resolve) => {
|
||||
const registerObserver = () => {
|
||||
const { unregister } = eventManager.register(
|
||||
`${selector}`,
|
||||
{
|
||||
customCheck: (element) => element.matches(selector),
|
||||
},
|
||||
async (element) => {
|
||||
resolve(element);
|
||||
await delay(1);
|
||||
unregister(); // Remove the listener once the element is found
|
||||
},
|
||||
);
|
||||
return unregister;
|
||||
};
|
||||
|
||||
let unregister = null;
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
// DOM is still loading, wait for it to be ready
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
unregister = registerObserver();
|
||||
});
|
||||
} else {
|
||||
unregister = registerObserver();
|
||||
}
|
||||
|
||||
const querySelector = () => document.querySelector(selector);
|
||||
const element = querySelector();
|
||||
|
||||
if (element) {
|
||||
if (unregister) unregister();
|
||||
resolve(element);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user