Merge pull request #357 from Jones8683/main

This commit is contained in:
Alphons Joseph
2025-11-29 09:38:26 +08:00
committed by GitHub
8 changed files with 293 additions and 381 deletions
+101 -75
View File
@@ -158,6 +158,16 @@ select {
color: var(--text-primary);
position: relative;
}
#main {
> .timetablepage {
> .quickbar {
.gutter {
border-bottom-left-radius: 15px;
border-bottom-right-radius: 15px;
}
}
}
}
.forums {
color: var(--text-color);
}
@@ -823,11 +833,18 @@ div > ol:has(.uiFileHandlerWrapper) {
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.2);
}
html.transparencyEffects [class*="ResourceList__ResourceItem___voTSd"],
html.transparencyEffects [class*="ResourceList__ResourceItem___voTSd"] [class*="ResourceList__name___ydvDT"] {
html.transparencyEffects [class*="BasicPanel__BasicPanel___q92_U"] > ol > li {
border-bottom: none !important;
}
html.transparencyEffects
[class*="BasicPanel__BasicPanel___q92_U"]
> ol
> li
+ li {
border-top: 1px solid var(--theme-offset-bg);
}
.assessmentsWrapper .message {
display: none;
}
@@ -983,7 +1000,7 @@ html.transparencyEffects [class*="ResourceList__ResourceItem___voTSd"] [class*="
top: 72px;
left: 0px;
z-index: 10;
@media (min-width: 1401px) {
position: absolute;
left: 402px;
@@ -1690,7 +1707,7 @@ iframe.userHTML {
}
.programmeNavigator {
box-shadow: 0 0 40px 0px rgba(0,0,0,0.05);
box-shadow: 0 0 40px 0px rgba(0, 0, 0, 0.05);
overflow-y: scroll;
height: 100%;
@@ -1749,7 +1766,7 @@ iframe.userHTML {
&.selected {
background: transparent !important;
}
&::before {
content: "";
position: absolute;
@@ -1761,7 +1778,9 @@ iframe.userHTML {
background: var(--auto-background);
opacity: 0;
scale: 0.95;
transition: opacity 0.2s ease-out, scale 0.1s ease-out;
transition:
opacity 0.2s ease-out,
scale 0.1s ease-out;
z-index: -1;
pointer-events: none;
}
@@ -1775,13 +1794,12 @@ iframe.userHTML {
opacity: 1;
scale: 1;
}
}
}
}
.pane {
.content:has(.programmeNavigator) {
.content:has(.programmeNavigator) {
margin: 0;
}
@@ -1799,7 +1817,9 @@ iframe.userHTML {
.dark .programmeNavigator .navigator {
.search {
background: var(--background-secondary) !important;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1), inset 0px 0px 15px 0px rgba(0, 0, 0, 0.1) !important;
box-shadow:
0px 0px 10px 0px rgba(0, 0, 0, 0.1),
inset 0px 0px 15px 0px rgba(0, 0, 0, 0.1) !important;
}
}
.dark #main > .course > .content > h1 {
@@ -2028,7 +2048,7 @@ div.entry.new {
div.liveEntry {
border-radius: 4px;
}
}
div.dailycalMarker {
border-radius: 4px;
@@ -2179,24 +2199,23 @@ div.bar.flat {
background: var(--background-secondary) !important;
}
.dashlet-motd {
padding: 7px !important;
.message {
font-size: 24px !important;
border-radius: 12px !important;
border: none !important;
box-shadow: none !important;
color: #fff !important;
padding: 16px !important;
margin: 0 !important;
height: 100% !important;
max-height: none !important;
display: flex !important;
align-items: flex-start !important;
overflow: hidden !important;
.dashlet-motd {
padding: 7px !important;
.message {
font-size: 24px !important;
border-radius: 12px !important;
border: none !important;
box-shadow: none !important;
color: #fff !important;
padding: 16px !important;
margin: 0 !important;
height: 100% !important;
max-height: none !important;
display: flex !important;
align-items: flex-start !important;
overflow: hidden !important;
}
}
}
.cke_toolbox > .cke_toolbar > .cke_toolgroup > .cke_button {
background: var(--background-secondary) !important;
@@ -3750,14 +3769,19 @@ div.day-empty {
}
.notice-unified-content {
h1, h2, h3, h4, h5, h6 {
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0 !important;
padding: 0 !important;
font-weight: inherit !important;
color: inherit !important;
text-shadow: none !important;
}
.notice-header {
display: flex;
justify-content: space-between;
@@ -3766,7 +3790,7 @@ div.day-empty {
margin-bottom: 12px;
gap: 16px;
}
.notice-content-title {
font-size: 20px !important; // Nice middle ground - not too big, not too small
font-weight: 600 !important;
@@ -3775,7 +3799,7 @@ div.day-empty {
line-height: 1.3 !important;
flex-shrink: 0;
}
.notice-content-body {
font-size: 14px !important;
color: var(--text-secondary) !important;
@@ -3787,72 +3811,73 @@ div.day-empty {
min-width: 600px; // Ensure tables have consistent width for layout
width: 100%;
}
// The ONLY difference between states is clipping!
&.notice-card-state {
&.notice-card-state {
.notice-content-body {
// Clip to show only 2 lines but keep full layout
overflow: hidden;
max-height: 3em; // ~2 lines worth of height
}
}
&.notice-modal-state {
.notice-close-btn {
opacity: 1;
}
.notice-content-body {
// Show full content with scrolling
overflow-y: auto;
// Custom scrollbar for long content
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.3);
}
// Style content elements nicely
p {
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.3);
}
a {
color: var(--theme-primary);
text-decoration: none;
// Style content elements nicely
p {
margin-bottom: 12px;
&:hover {
text-decoration: underline;
}
}
&:last-child {
margin-bottom: 0;
}
}
ul, ol {
margin: 12px 0;
padding-left: 20px;
}
a {
color: var(--theme-primary);
text-decoration: none;
li {
margin-bottom: 4px;
}
}
}
}
&:hover {
text-decoration: underline;
}
}
ul,
ol {
margin: 12px 0;
padding-left: 20px;
}
li {
margin-bottom: 4px;
}
}
}
}
.notice-header {
display: flex;
@@ -3952,21 +3977,21 @@ button.notice-close-btn {
color: var(--text-secondary);
flex: 1;
overflow-y: auto;
// Custom scrollbar
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.3);
}
@@ -3974,7 +3999,7 @@ button.notice-close-btn {
// Style content elements
p {
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
@@ -3989,7 +4014,8 @@ button.notice-close-btn {
}
}
ul, ol {
ul,
ol {
margin: 12px 0;
padding-left: 20px;
}
@@ -4003,7 +4029,7 @@ button.notice-close-btn {
.dark {
.notice-card {
border-color: rgba(255, 255, 255, 0.05);
&:hover {
border-color: rgba(255, 255, 255, 0.1);
}
@@ -4036,7 +4062,7 @@ button.notice-close-btn {
.notice-card {
padding: 12px;
}
.notice-preview {
font-size: 13px;
}
+3 -3
View File
@@ -11,8 +11,8 @@
import { closeExtensionPopup } from "@/seqta/utils/Closers/closeExtensionPopup";
import { OpenAboutPage } from "@/seqta/utils/Openers/OpenAboutPage";
import { OpenWhatsNewPopup } from "@/seqta/utils/Whatsnew";
import { OpenMinecraftServerPopup } from "@/seqta/utils/AboutMinecraftServer";
import { OpenWhatsNewPopup } from "@/seqta/utils/Openers/OpenWhatsNewPopup";
import { OpenMinecraftServerPopup } from "@/seqta/utils/Openers/OpenMinecraftServerPopup";
import ColourPicker from "../components/ColourPicker.svelte";
import { settingsPopup } from "../hooks/SettingsPopup";
@@ -103,7 +103,7 @@
{#if !standalone}
<button
onclick={openAbout}
class="absolute top-1 right-[62px] w-8 h-8 text-lg rounded-xl font-IconFamily bg-zinc-100 dark:bg-zinc-700"
class="absolute top-1 right-[63px] w-8 h-8 text-lg rounded-xl font-IconFamily bg-zinc-100 dark:bg-zinc-700"
>
{"\ueb73"}
</button>
@@ -39,7 +39,7 @@ const notificationCollectorPlugin: Plugin<{}, NotificationCollectorStorage> = {
"[class*='notifications__bubble___']",
) as HTMLElement;
if (api.storage.lastNotificationCount !== 0) {
if (alertDiv && api.storage.lastNotificationCount !== 0) {
alertDiv.textContent = api.storage.lastNotificationCount.toString();
}
@@ -63,7 +63,7 @@ const notificationCollectorPlugin: Plugin<{}, NotificationCollectorStorage> = {
const notificationCount = data.payload.notifications.length;
api.storage.lastNotificationCount = notificationCount;
api.storage.lastCheckedTime = new Date().toISOString();
// Reset error count on success
api.storage.consecutiveErrors = 0;
@@ -74,31 +74,36 @@ const notificationCollectorPlugin: Plugin<{}, NotificationCollectorStorage> = {
}
} catch (error) {
console.error("[BetterSEQTA+] Error fetching notifications:", error);
api.storage.consecutiveErrors = (api.storage.consecutiveErrors || 0) + 1;
api.storage.consecutiveErrors =
(api.storage.consecutiveErrors || 0) + 1;
}
};
const getNextInterval = () => {
// Exponential backoff on errors, max 5 minutes
const errorMultiplier = Math.min(Math.pow(2, api.storage.consecutiveErrors || 0), 10);
const errorMultiplier = Math.min(
Math.pow(2, api.storage.consecutiveErrors || 0),
10,
);
return Math.min(baseInterval * errorMultiplier, maxInterval);
};
const startPolling = () => {
if (pollInterval) return; // Already polling
checkNotifications();
const scheduleNext = () => {
const interval = getNextInterval();
pollInterval = window.setTimeout(() => {
checkNotifications().then(() => {
if (pollInterval) { // Only continue if not stopped
if (pollInterval) {
// Only continue if not stopped
scheduleNext();
}
});
}, interval);
};
scheduleNext();
};
@@ -124,14 +129,16 @@ const notificationCollectorPlugin: Plugin<{}, NotificationCollectorStorage> = {
isVisible = !document.hidden;
if (isVisible && !pollInterval) {
// Resume polling when tab becomes visible
const alertDiv = document.querySelector("[class*='notifications__bubble___']");
const alertDiv = document.querySelector(
"[class*='notifications__bubble___']",
);
if (alertDiv) {
startPolling();
}
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
document.addEventListener("visibilitychange", handleVisibilityChange);
api.seqta.onMount("[class*='notifications__bubble___']", (_) => {
startPolling();
@@ -139,7 +146,7 @@ const notificationCollectorPlugin: Plugin<{}, NotificationCollectorStorage> = {
return () => {
stopPolling();
document.removeEventListener('visibilitychange', handleVisibilityChange);
document.removeEventListener("visibilitychange", handleVisibilityChange);
};
},
};
+2 -5
View File
@@ -23,12 +23,9 @@ import { updateAllColors } from "@/seqta/ui/colors/Manager";
import loading from "@/seqta/ui/Loading";
import { SendNewsPage } from "@/seqta/utils/SendNewsPage";
import { loadHomePage } from "@/seqta/utils/Loaders/LoadHomePage";
import { OpenWhatsNewPopup } from "@/seqta/utils/Whatsnew";
//import { OpenMinecraftServerPopup } from "@/seqta/utils/AboutMinecraftServer";
import { OpenWhatsNewPopup } from "@/seqta/utils/Openers/OpenWhatsNewPopup";
import {
updateTimetableTimes,
} from "@/seqta/utils/updateTimetableTimes";
import { updateTimetableTimes } from "@/seqta/utils/updateTimetableTimes";
// JSON content
import MenuitemSVGKey from "@/seqta/content/MenuItemSVGKey.json";
+10 -64
View File
@@ -1,25 +1,17 @@
import stringToHTML from "../stringToHTML";
import { settingsState } from "../listeners/SettingsState";
import { animate, stagger } from "motion";
import { DeleteWhatsNew } from "../Whatsnew";
import { openPopup } from "./PopupManager";
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(
const header = stringToHTML(
/* html */
`<div class="whatsnewHeader">
<h1>About</h1>
<p>About the extension</p>
</div>`,
).firstChild;
).firstChild as HTMLElement;
let text = stringToHTML(/* html */ `
const text = stringToHTML(/* html */ `
<div class="whatsnewTextContainer" style="overflow-y: hidden;">
<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" />
<p>BetterSEQTA+ is a fork of BetterSEQTA (originally developed by Nulkem), which was discontinued. BetterSEQTA+ continued development of BetterSEQTA, while incorporating a plethora of features. </p>
@@ -37,9 +29,9 @@ export function OpenAboutPage() {
style="width: 100%; max-width: 500px; height: auto; object-fit: contain; display: block; margin: -110px auto 0;">
</div>
</div>
`).firstChild;
`).firstChild as HTMLElement;
let footer = stringToHTML(/* html */ `
const footer = stringToHTML(/* html */ `
<div class="whatsnewFooter">
<div>
Resources and Feedback:
@@ -67,56 +59,10 @@ export function OpenAboutPage() {
</a>
</div>
</div>
`).firstChild;
`).firstChild as HTMLElement;
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();
}
});
var closeelement = document.getElementById("whatsnewclosebutton");
closeelement!.addEventListener("click", function () {
DeleteWhatsNew();
openPopup({
header,
content: [text, footer],
});
}
@@ -1,24 +1,5 @@
import { settingsState } from "./listeners/SettingsState";
import { animate, stagger } from "motion";
import stringToHTML from "./stringToHTML";
export async function DeleteWhatsNew() {
const bkelement = document.getElementById("whatsnewbk");
const popup = document.querySelector(".whatsnewContainer") as HTMLElement;
if (!settingsState.animations) {
bkelement?.remove();
return;
}
animate(
[popup, bkelement!],
{ opacity: [1, 0], scale: [1, 0] },
{ ease: [0.22, 0.03, 0.26, 1] },
).then(() => {
bkelement?.remove();
});
}
import stringToHTML from "../stringToHTML";
import { openPopup } from "./PopupManager";
export function OpenMinecraftServerPopup() {
if (!document.querySelector('link[href*="minecraftia"]')) {
@@ -28,45 +9,36 @@ export function OpenMinecraftServerPopup() {
document.head.appendChild(fontLink);
}
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(
const header = stringToHTML(
/* html */
`<div class="whatsnewHeader">
<h1>Minecraft Server</h1>
<p>The official BetterSEQTA+ Minecraft Server</p>
</div>`,
).firstChild;
).firstChild as HTMLElement;
let imagecont = document.createElement("div");
imagecont.classList.add("whatsnewImgContainer");
const imageContainer = document.createElement("div");
imageContainer.classList.add("whatsnewImgContainer");
let video = document.createElement("video");
const video = document.createElement("video");
video.style.aspectRatio = "16/9";
video.style.background = "black";
let source = document.createElement("source");
const source = document.createElement("source");
source.setAttribute(
"src",
"https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/server-video.mp4",
);
video.autoplay = true;
video.muted = true;
video.loop = true;
video.appendChild(source);
video.classList.add("whatsnewImg");
imagecont.appendChild(video);
imageContainer.appendChild(video);
let textcontainer = document.createElement("div");
textcontainer.classList.add("whatsnewTextContainer");
let text = stringToHTML(/* html */ `
<div class="whatsnewTextContainer" style="height: 50%; overflow-y: scroll;">
const text = stringToHTML(/* html */ `
<div class="whatsnewTextContainer" style="height: 50%; overflow-y: hidden;">
<h1>Join our community in Minecraft!</h1>
<p style="margin-left: 0;">Join the official BetterSEQTA+ Minecraft Server community now!</p>
@@ -92,8 +64,7 @@ export function OpenMinecraftServerPopup() {
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
">
1px 1px 0 #000;">
mc.betterseqta.org
</p>
<p style="
@@ -107,14 +78,13 @@ export function OpenMinecraftServerPopup() {
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
">
1px 1px 0 #000;">
Version: 1.21.4
</p>
</div>
`).firstChild;
`).firstChild as HTMLElement;
let footer = stringToHTML(/* html */ `
const footer = stringToHTML(/* html */ `
<div class="whatsnewFooter">
<div>
Resources and Feedback:
@@ -144,59 +114,10 @@ export function OpenMinecraftServerPopup() {
<div>
</div>
</div>
`).firstChild;
`).firstChild as HTMLElement;
let exitbutton = document.createElement("div");
exitbutton.id = "whatsnewclosebutton";
container.append(
openPopup({
header,
imagecont,
text as HTMLElement,
footer as HTMLElement,
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();
}
});
var closeelement = document.getElementById("whatsnewclosebutton");
closeelement!.addEventListener("click", function () {
DeleteWhatsNew();
content: [imageContainer, text, footer],
});
}
@@ -1,48 +1,22 @@
import { settingsState } from "./listeners/SettingsState";
import { animate, stagger } from "motion";
import stringToHTML from "./stringToHTML";
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];
if (!settingsState.animations) {
bkelement?.remove();
return;
}
animate(
[popup, bkelement!],
{ opacity: [1, 0], scale: [1, 0] },
{ ease: [0.22, 0.03, 0.26, 1] },
).then(() => {
bkelement?.remove();
});
}
import { openPopup } from "./PopupManager";
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(
const header = stringToHTML(
/* html */
`<div class="whatsnewHeader">
<h1>What's New</h1>
<p>BetterSEQTA+ V${browser.runtime.getManifest().version}</p>
</div>`,
).firstChild;
).firstChild as HTMLElement;
let imagecont = document.createElement("div");
imagecont.classList.add("whatsnewImgContainer");
const imageContainer = document.createElement("div");
imageContainer.classList.add("whatsnewImgContainer");
let video = document.createElement("video");
let source = document.createElement("source");
const video = document.createElement("video");
const source = document.createElement("source");
source.setAttribute(
"src",
@@ -53,19 +27,10 @@ export function OpenWhatsNewPopup() {
video.loop = true;
video.appendChild(source);
video.classList.add("whatsnewImg");
imagecont.appendChild(video);
imageContainer.appendChild(video);
/* let whatsnewimg = document.createElement("img");
//whatsnewimg.src = "https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/update-image.webp";
whatsnewimg.src = browser.runtime.getURL('../../resources/update-image.webp');
whatsnewimg.classList.add("whatsnewImg");
imagecont.appendChild(whatsnewimg); */
let textcontainer = document.createElement("div");
textcontainer.classList.add("whatsnewTextContainer");
let text = stringToHTML(/* html */ `
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: scroll;">
const text = stringToHTML(/* html */ `
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: auto;">
<h1>3.4.11 - New Features & Bug Fixes</h1>
<li>Added Background Music plugin</li>
@@ -133,7 +98,7 @@ export function OpenWhatsNewPopup() {
<li>Fixed discord icon colour in light mode</li>
<li>Fixed subject averages not showing up with letter grades</li>
<li>Tweaked compose UI</li>
<h1>3.4.4 - Bug Fixes and Improvements</h1>
<li>Added vertical zoom to the timetable</li>
<li>Fixed theme importing failing when images were included</li>
@@ -147,15 +112,15 @@ export function OpenWhatsNewPopup() {
<li>Fixed theme application in the creator</li>
<li>Performance improvements</li>
<li>Other minor bug fixes</li>
<h1>3.4.3 - Minor Bug Fixes</h1>
<li>Fixed a bug where timetable colours couldn't be changed</li>
<li>Other minor bug fixes</li>
<h1>3.4.2 - Minor Bug Fixes</h1>
<li>Fixed a bug where Assessment Average wasn't enabled by default</li>
<li>Fixed floating menus would sometimes be placed behind other elements</li>
<h1>3.4.1 - Bug Fixes and Performance Improvements</h1>
<li>Added a new "Subject Average" section to the assessments page</li>
<li>Fixed a bug where animations wouldn't play correctly</li>
@@ -164,7 +129,7 @@ export function OpenWhatsNewPopup() {
<li>Improved animation performance</li>
<li>Better Animations!</li>
<li>Minor style tweaks</li>
<h1>3.4.0 - Major Performance Update</h1>
<li>Completely rebuilt the extension popup using Svelte for dramatically improved performance</li>
<li>Added a brand new background store with search functionality and downloadable backgrounds</li>
@@ -173,10 +138,10 @@ export function OpenWhatsNewPopup() {
<li>Smoother animations and improved scrolling</li>
<li>Fixed Firefox compatibility issues</li>
<li>Other minor bug fixes and under the hood improvements</li>
<h1>3.3.1 - Hot Fix</h1>
<li>Fixed assessments not loading when no notices are available</li>
<h1>3.3.0 - Overhauled Theming System</h1>
<li>Added a theme store!</li>
<li>Added the new theme creator!</li>
@@ -190,12 +155,12 @@ export function OpenWhatsNewPopup() {
<li>Made animations toggle apply to settings</li>
<li>Small styling improvements</li>
<li>Other minor bug fixes</li>
<h1>3.2.7 - Minor Improvements</h1>
<li>Improved performance!</li>
<li>Fixed a bug where the icon wasn't showing up</li>
<h1>3.2.6 - Bug fixes and performance improvements</h1>
<li>Improved contrast for notifications</li>
<li>Added 12-hour time format toggle</li>
@@ -209,7 +174,7 @@ export function OpenWhatsNewPopup() {
<li>Enabled spellcheck inside of direct messages</li>
<li>Fixed timetable dates being misaligned</li>
<li>Other minor bug fixes and under the hood improvements</li>
<h1>3.2.5 - More Bug Fixes</h1>
<li>New direct message scroll animations</li>
<li>Added error message for brave browser shields breaking backgrounds</li>
@@ -218,7 +183,7 @@ export function OpenWhatsNewPopup() {
<li>Made settings panel auto size to height of screen</li>
<li>Fixed timetable dates not visible</li>
<li>Other minor bug fixes</li>
<h1>3.2.4 - Bug Fixes</h1>
<li>Added an open changelog button to settings</li>
<li>Fixed a memory overflow bug with Education Perfect</li>
@@ -226,74 +191,74 @@ export function OpenWhatsNewPopup() {
<li>Fixed news feed not loading</li>
<li>Fixed home items duplicating</li>
<li>Fixed Upcoming assessments not showing</li>
<h1>3.2.2 - Minor Improvements</h1>
<li>Added Settings open-close animation</li>
<li>Minor Bug Fixes</li>
<h1>3.2.0 - Custom Themes</h1>
<li>Added transparency (blur) effects</li>
<li>Added custom themes</li>
<li>Added colour picker history</li>
<li>Heaps of bug fixes</li>
<h1>3.1.3 - Custom Backgrounds</h1>
<li>Added custom backgrounds with support for images and videos</li>
<li>Overhauled topbar</li>
<li>New animated hamburger icon</li>
<li>Minor bug fixes</li>
<h1>3.1.2 - New settings menu!</h1>
<li>Overhauled the settings menu</li>
<li>Added custom gradients</li>
<li>Added HEAPS of animations</li>
<li>Fixed a bug where shortcuts don't show up</li>
<li>Other minor bugs fixed</li>
<h1>3.1.1 - Minor Bug fixes</h1>
<li>Fixed assessments overlapping</li>
<li>Fixed houses not displaying if they aren't a specific color</li>
<li>Fixed Chrome Webstore Link</li>
<h1>3.1.0 - Design Improvements</h1>
<li>Minor UI improvements</li>
<li>Added Animation Speed Slider</li>
<li>Animation now enables and disables without reloading SEQTA</li>
<li>Changed logo</li>
<h1>3.0.0 - BetterSEQTA+ *Complete Overhaul*</h1>
<li>Redesigned appearance</li>
<li>Upgraded to manifest V3 (longer support)</li>
<li>Fixed transitional glitches</li>
<li>Under the hood improvements</li>
<li>Fixed News Feed</li>
<h1>2.0.7 - Added support to other domains + Minor bug fixes</h1>
<li>Fixed BetterSEQTA+ not loading on some pages</li>
<li>Fixed text colour of notices being unreadable</li>
<li>Fixed pages not reloading when saving changes</li>
<h1>2.0.2 - Minor bug fixes</h1>
<li>Fixed indicator for current lesson</li>
<li>Fixed text colour for DM messages list in Light mode</li>
<li>Fixed user info text colour</li>
<h1>Sleek New Layout</h1>
<li>Updated with a new font and presentation, BetterSEQTA+ has never looked better.</li>
<h1>New Updated Sidebar</h1>
<li>Condensed appearance with new updated icons.</li>
<h1>Independent Light Mode and Dark Mode</h1>
<li>Dark mode and Light mode are now available to pick alongside your chosen Theme Colour. Your Theme Colour will now become an accent colour for the page.
Light/Dark mode can be toggled with the new button, found in the top-right of the menu bar.</li>
<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;
`).firstChild as HTMLElement;
let footer = stringToHTML(/* html */ `
const footer = stringToHTML(/* html */ `
<div class="whatsnewFooter">
<div>
Resources and Feedback:
@@ -321,63 +286,15 @@ export function OpenWhatsNewPopup() {
</a>
</div>
<div>
<a href="https://ko-fi.com/sethburkart" target="_blank" style="background: none !important; margin:0;margin-left:6px; padding:0; display: flex; align-items: center;">
<a href="https://ko-fi.com/sethburkart" target="_blank" style="background: none !important; margin:0;margin-left:6px;padding:0; display: flex; align-items: center;">
<img height="25" style="border:0px; height:25px; margin-right: -6px;" src="${kofi}" border="0" alt="Buy Me a Coffee at ko-fi.com" />
</a>
</div>
</div>
`).firstChild;
`).firstChild as HTMLElement;
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();
}
});
var closeelement = document.getElementById("whatsnewclosebutton");
closeelement!.addEventListener("click", function () {
DeleteWhatsNew();
openPopup({
header,
content: [imageContainer, text, footer],
});
}
+98
View File
@@ -0,0 +1,98 @@
import { settingsState } from "../listeners/SettingsState";
import { animate as motionAnimate, stagger } from "motion";
type AnimationTarget = string | Element | Element[] | NodeList | null;
let isClosing = false;
export async function closePopup() {
if (isClosing) return;
isClosing = true;
const background = document.getElementById("whatsnewbk");
const popup = document.getElementsByClassName("whatsnewContainer")[0] as
| HTMLElement
| undefined;
if (!background || !popup) {
isClosing = false;
return;
}
if (!settingsState.animations) {
background.remove();
isClosing = false;
return;
}
await (motionAnimate as any)(
[popup, background],
{ opacity: [1, 0], scale: [1, 0.95] },
{ duration: 0.25, easing: [0.22, 0.03, 0.26, 1] },
);
background.remove();
isClosing = false;
}
interface OpenPopupOptions {
header?: Node | null;
content?: (Node | null | undefined)[];
animateSelector?: AnimationTarget;
}
export function openPopup({
header,
content = [],
animateSelector = ".whatsnewTextContainer *",
}: OpenPopupOptions = {}) {
const background = document.createElement("div");
background.id = "whatsnewbk";
background.classList.add("whatsnewBackground");
const container = document.createElement("div");
container.classList.add("whatsnewContainer");
if (header) container.append(header);
for (const node of content) if (node) container.append(node);
const closeButton = document.createElement("div");
closeButton.id = "whatsnewclosebutton";
container.append(closeButton);
background.append(container);
document.getElementById("container")!.append(background);
if (settingsState.animations) {
(motionAnimate as any)(
[container, background],
{ scale: [0, 1] },
{ type: "spring", stiffness: 220, damping: 18 },
);
if (animateSelector) {
const targets =
typeof animateSelector === "string"
? document.querySelectorAll(animateSelector)
: animateSelector;
(motionAnimate as any)(
targets!,
{ opacity: [0, 1], y: [10, 0] },
{
delay: stagger(0.05, { startDelay: 0.1 }),
duration: 0.5,
easing: [0.22, 0.03, 0.26, 1],
},
);
}
}
delete settingsState.justupdated;
background.addEventListener("click", (event) => {
if (event.target === background) void closePopup();
});
closeButton.addEventListener("click", () => void closePopup());
}