mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 11:44:40 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a151e7a07e | |||
| 5b590512ee | |||
| 3ff8ef144a | |||
| d9abed1c5d | |||
| 82a789bbec | |||
| ce6538f850 | |||
| 979ae7149f | |||
| 6e71437fe8 | |||
| 940ecf8714 | |||
| e0cc2e0fdf | |||
| 5a19ef92e8 | |||
| 0a3781e9c2 | |||
| a2e39c9d84 | |||
| 520abbb5c3 | |||
| d0a11da15f | |||
| fd5802f9a3 | |||
| 380d829d19 | |||
| 702528fb0c | |||
| 2c077bc755 | |||
| fd86e57442 | |||
| 60ce18280e | |||
| 668dbfd78b | |||
| 810aa17f15 | |||
| b64558e50a | |||
| 9b969bd708 | |||
| 1945f7c592 | |||
| 3e26d9af3c | |||
| 3c8d7e246b | |||
| 2e56518330 | |||
| e67f3110e0 | |||
| a67f4d2e25 | |||
| d6025140fd | |||
| 88e9ddf29c | |||
| 11adc4f933 | |||
| 15691e8d94 | |||
| 754b8d0589 | |||
| 1d634d0da1 | |||
| 7136de90be | |||
| 466628479e | |||
| 9c08d0bac2 | |||
| 6c5320007f | |||
| 4734a443b4 | |||
| 7c38e1dc29 |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "betterseqtaplus",
|
||||
"version": "3.4.11",
|
||||
"version": "3.4.13",
|
||||
"type": "module",
|
||||
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development add add heaps more features!",
|
||||
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ function getDefaultValues(): SettingsState {
|
||||
originalSelectedColor: "",
|
||||
DarkMode: true,
|
||||
animations: !isLowEndDevice,
|
||||
assessmentsAverage: true,
|
||||
assessmentsAverage: false,
|
||||
defaultPage: "home",
|
||||
shortcuts: [
|
||||
{
|
||||
|
||||
+129
-87
@@ -57,7 +57,8 @@ select {
|
||||
transition: 200ms;
|
||||
background: var(--auto-background) !important;
|
||||
}
|
||||
* {
|
||||
:root * {
|
||||
font-family: Rubik, sans-serif !important;
|
||||
--theme-fg-parts: white;
|
||||
}
|
||||
.extension-editor {
|
||||
@@ -158,6 +159,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);
|
||||
}
|
||||
@@ -813,8 +824,8 @@ div > ol:has(.uiFileHandlerWrapper) {
|
||||
[aria-labelledby="lixycoxs-tab-1"] [minlength="0"] {
|
||||
min-height: 128px !important;
|
||||
}
|
||||
.student #menu > ul::before {
|
||||
background-image: var(--betterseqta-logo);
|
||||
body.student #menu > ul::before {
|
||||
background-image: var(--betterseqta-logo) !important;
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
@@ -823,11 +834,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 +1001,7 @@ html.transparencyEffects [class*="ResourceList__ResourceItem___voTSd"] [class*="
|
||||
top: 72px;
|
||||
left: 0px;
|
||||
z-index: 10;
|
||||
|
||||
|
||||
@media (min-width: 1401px) {
|
||||
position: absolute;
|
||||
left: 402px;
|
||||
@@ -1026,8 +1044,8 @@ html.transparencyEffects [class*="ResourceList__ResourceItem___voTSd"] [class*="
|
||||
display: none;
|
||||
}
|
||||
#title {
|
||||
background: var(--background-primary);
|
||||
color: var(--text-primary);
|
||||
background: var(--background-primary) !important;
|
||||
color: var(--text-primary) !important;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-right: 56px !important;
|
||||
@@ -1690,7 +1708,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 +1767,7 @@ iframe.userHTML {
|
||||
&.selected {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@@ -1761,7 +1779,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 +1795,12 @@ iframe.userHTML {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pane {
|
||||
.content:has(.programmeNavigator) {
|
||||
.content:has(.programmeNavigator) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -1799,7 +1818,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 +2049,7 @@ div.entry.new {
|
||||
|
||||
div.liveEntry {
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
div.dailycalMarker {
|
||||
border-radius: 4px;
|
||||
@@ -2179,24 +2200,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;
|
||||
padding: 16px !important;
|
||||
margin: 0 !important;
|
||||
height: 100% !important;
|
||||
max-height: none !important;
|
||||
display: flex !important;
|
||||
align-items: flex-start !important;
|
||||
overflow: hidden !important;
|
||||
color: var(--text-primary) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.cke_toolbox > .cke_toolbar > .cke_toolgroup > .cke_button {
|
||||
background: var(--background-secondary) !important;
|
||||
@@ -3339,6 +3359,22 @@ div.day-empty {
|
||||
color: var(--text-primary);
|
||||
transform-origin: center center;
|
||||
}
|
||||
.whatsnewTextContainer.privacyStatement p {
|
||||
margin-bottom: 1.5ex;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.whatsnewTextContainer.privacyStatement a {
|
||||
background: rgba(184, 184, 184, 0.1);
|
||||
border-radius: 0.5rem;
|
||||
margin-left: 0.25rem;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
.dark .whatsnewTextContainer.privacyStatement a {
|
||||
background: rgba(7, 7, 7, 0.1);
|
||||
}
|
||||
.whatsnewHeader {
|
||||
margin: 20px;
|
||||
width: 100%;
|
||||
@@ -3373,6 +3409,7 @@ div.day-empty {
|
||||
.whatsnewImg {
|
||||
margin: 0 auto;
|
||||
width: 90%;
|
||||
aspect-ratio: 16 / 10;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
@@ -3399,7 +3436,6 @@ div.day-empty {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
color: #9a3412;
|
||||
background-color: #ffedd569;
|
||||
border-radius: 9999px;
|
||||
border: 1px solid rgba(253, 186, 140, 0.3);
|
||||
background-color: #ffedd5;
|
||||
@@ -3750,14 +3786,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,16 +3807,16 @@ 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;
|
||||
color: var(--text-primary) !important;
|
||||
margin: 0 0 12px 0 !important;
|
||||
margin: 0 0 12px !important;
|
||||
line-height: 1.3 !important;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
||||
.notice-content-body {
|
||||
font-size: 14px !important;
|
||||
color: var(--text-secondary) !important;
|
||||
@@ -3787,72 +3828,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;
|
||||
@@ -3882,7 +3924,6 @@ button.notice-close-btn {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
color: var(--text-primary);
|
||||
transition: all 0.2s ease !important;
|
||||
flex-shrink: 0;
|
||||
@@ -3940,33 +3981,33 @@ button.notice-close-btn {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin: 16px 20px 20px 20px;
|
||||
margin: 16px 20px 20px;
|
||||
line-height: 1.3;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notice-modal-body {
|
||||
padding: 0 20px 20px 20px;
|
||||
padding: 0 20px 20px;
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
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 +4015,7 @@ button.notice-close-btn {
|
||||
// Style content elements
|
||||
p {
|
||||
margin-bottom: 12px;
|
||||
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -3989,7 +4030,8 @@ button.notice-close-btn {
|
||||
}
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
ul,
|
||||
ol {
|
||||
margin: 12px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
@@ -4003,7 +4045,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);
|
||||
}
|
||||
@@ -4026,17 +4068,17 @@ button.notice-close-btn {
|
||||
|
||||
.notice-modal-title {
|
||||
font-size: 20px;
|
||||
margin: 12px 16px 16px 16px;
|
||||
margin: 12px 16px 16px;
|
||||
}
|
||||
|
||||
.notice-modal-body {
|
||||
padding: 0 16px 16px 16px;
|
||||
padding: 0 16px 16px;
|
||||
}
|
||||
|
||||
.notice-card {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
|
||||
.notice-preview {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"last_updated": "2024-06-15T12:00:00Z",
|
||||
"whatsnew_html": "<div class=\"whatsnewTextContainer\" style=\"overflow-y: auto; font-size: 1.3rem; line-height: 1.6;\"><p>It has come to our attention that several schools have expressed concerns about BetterSEQTA+. This is very disheartening, so we have decided to release a statement on the situation.</p><p>To view our privacy policy, please click the <strong>shield icon</strong> in the settings menu, or <a href=\"https://betterseqta.org/privacy\" target=\"_blank\" rel=\"noopener noreferrer\" id=\"privacy-link\" style=\"color: inherit; text-decoration: underline; cursor: pointer; white-space: nowrap;\">click here</a>.</p><p style=\"font-weight: bold; margin-top: 15px;\">We never collect any information from you, and aim to provide the best features possible.</p></div>"
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition';
|
||||
import { animate } from 'motion';
|
||||
|
||||
let { onConfirm, onCancel, title, message } = $props<{
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
title: string;
|
||||
message: string;
|
||||
}>();
|
||||
|
||||
let modalElement: HTMLElement;
|
||||
|
||||
$effect(() => {
|
||||
if (modalElement) {
|
||||
animate(
|
||||
modalElement,
|
||||
{ scale: [0.9, 1], opacity: [0, 1] },
|
||||
{
|
||||
type: 'spring',
|
||||
stiffness: 300,
|
||||
damping: 25
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex fixed inset-0 z-[10000] justify-center items-center bg-black/50"
|
||||
style="position: fixed; top: 0; left: 0; right: 0; bottom: 0;"
|
||||
onclick={(e) => {
|
||||
if (e.target === e.currentTarget) onCancel();
|
||||
}}
|
||||
onkeydown={(e) => {
|
||||
if (e.key === 'Escape') onCancel();
|
||||
}}
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
transition:fade={{ duration: 150 }}
|
||||
>
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
bind:this={modalElement}
|
||||
class="p-4 mx-4 w-full max-w-md bg-white rounded-2xl shadow-2xl dark:bg-zinc-800"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
onkeydown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<h2 class="mb-3 text-xl font-bold text-gray-900 dark:text-white">
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
<div class="mb-6 text-lg text-gray-700 whitespace-pre-line dark:text-gray-300">
|
||||
{message}
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3 justify-end">
|
||||
<button
|
||||
onclick={onCancel}
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 rounded-lg transition-colors hover:bg-gray-200 dark:bg-zinc-700 dark:text-gray-200 dark:hover:bg-zinc-600"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onclick={onConfirm}
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-green-600 rounded-lg shadow-inner transition-colors hover:bg-green-700 dark:bg-green-500 dark:hover:bg-green-600"
|
||||
>
|
||||
Enable
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,13 +11,16 @@
|
||||
|
||||
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 DisclaimerModal from "../components/DisclaimerModal.svelte";
|
||||
import { settingsPopup } from "../hooks/SettingsPopup";
|
||||
|
||||
let devModeSequence = "";
|
||||
let showDisclaimerModal = $state(false);
|
||||
let disclaimerCallbacks = $state<{ onConfirm: () => void, onCancel: () => void } | null>(null);
|
||||
|
||||
const handleDevModeToggle = () => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
@@ -50,14 +53,24 @@
|
||||
closeExtensionPopup();
|
||||
};
|
||||
|
||||
const openMinecraftServer = () => {
|
||||
/* const openMinecraftServer = () => {
|
||||
OpenMinecraftServerPopup();
|
||||
closeExtensionPopup();
|
||||
}; */
|
||||
|
||||
const openPrivacyStatement = () => {
|
||||
window.open("https://betterseqta.org/privacy", "_blank");
|
||||
closeExtensionPopup();
|
||||
};
|
||||
|
||||
let { standalone } = $props<{ standalone?: boolean }>();
|
||||
let showColourPicker = $state<boolean>(false);
|
||||
|
||||
const showDisclaimer = (onConfirm: () => void, onCancel: () => void) => {
|
||||
disclaimerCallbacks = { onConfirm, onCancel };
|
||||
showDisclaimerModal = true;
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
settingsPopup.addListener(() => {
|
||||
showColourPicker = false;
|
||||
@@ -101,25 +114,34 @@
|
||||
/>
|
||||
|
||||
{#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"
|
||||
>
|
||||
{"\ueb73"}
|
||||
</button>
|
||||
<div class="flex absolute top-1 right-1 gap-1 items-center">
|
||||
<button
|
||||
onclick={openAbout}
|
||||
class="flex justify-center items-center w-8 h-8 text-lg rounded-xl font-IconFamily bg-zinc-100 dark:bg-zinc-700"
|
||||
>
|
||||
{"\ueb73"}
|
||||
</button>
|
||||
|
||||
<button
|
||||
onclick={openChangelog}
|
||||
class="absolute top-1 right-10 w-8 h-8 text-lg rounded-xl font-IconFamily bg-zinc-100 dark:bg-zinc-700"
|
||||
>
|
||||
{"\ue929"}
|
||||
</button>
|
||||
<button
|
||||
onclick={openChangelog}
|
||||
class="flex justify-center items-center w-8 h-8 text-lg rounded-xl font-IconFamily bg-zinc-100 dark:bg-zinc-700"
|
||||
>
|
||||
{"\ue929"}
|
||||
</button>
|
||||
|
||||
<button
|
||||
onclick={openMinecraftServer}
|
||||
class="absolute top-1 right-1 w-8 h-8 bg-zinc-100 dark:bg-zinc-700 rounded-xl p-1"
|
||||
aria-label="Open Minecraft Server"
|
||||
>
|
||||
<button
|
||||
onclick={openPrivacyStatement}
|
||||
class="flex justify-center items-center w-8 h-8 text-lg rounded-xl font-IconFamily bg-zinc-100 dark:bg-zinc-700"
|
||||
aria-label="Privacy Statement"
|
||||
>
|
||||
{"\uecba"}
|
||||
</button>
|
||||
|
||||
<!-- <button
|
||||
onclick={openMinecraftServer}
|
||||
class="flex justify-center items-center p-1 w-8 h-8 rounded-xl bg-zinc-100 dark:bg-zinc-700"
|
||||
aria-label="Open Minecraft Server"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 64 70"
|
||||
@@ -247,7 +269,8 @@
|
||||
transform="translate(18,10)"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</button> -->
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -256,7 +279,7 @@
|
||||
{
|
||||
title: "Settings",
|
||||
Content: Settings,
|
||||
props: { showColourPicker: openColourPicker },
|
||||
props: { showColourPicker: openColourPicker, showDisclaimer },
|
||||
},
|
||||
{ title: "Shortcuts", Content: Shortcuts },
|
||||
{ title: "Themes", Content: Theme },
|
||||
@@ -272,3 +295,27 @@
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if showDisclaimerModal && disclaimerCallbacks}
|
||||
<DisclaimerModal
|
||||
title="Assessment Averages Disclaimer"
|
||||
message="This feature calculates a simple average of your assessment grades. It does not take into account:
|
||||
• Assessment weightings
|
||||
• Different grading scales
|
||||
• Other factors used in official reports
|
||||
|
||||
The displayed average may be inaccurate compared to your actual marks found in reports.
|
||||
|
||||
Do you want to enable this feature?"
|
||||
onConfirm={() => {
|
||||
disclaimerCallbacks?.onConfirm();
|
||||
showDisclaimerModal = false;
|
||||
disclaimerCallbacks = null;
|
||||
}}
|
||||
onCancel={() => {
|
||||
disclaimerCallbacks?.onCancel();
|
||||
showDisclaimerModal = false;
|
||||
disclaimerCallbacks = null;
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
import type { SettingsList } from "@/interface/types/SettingsProps"
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState.ts"
|
||||
import PickerSwatch from "@/interface/components/PickerSwatch.svelte"
|
||||
import { showPrivacyNotification } from "@/seqta/utils/Openers/OpenPrivacyNotification"
|
||||
import { closeExtensionPopup } from "@/seqta/utils/Closers/closeExtensionPopup"
|
||||
|
||||
import { getAllPluginSettings } from "@/plugins"
|
||||
import type { BooleanSetting, StringSetting, NumberSetting, SelectSetting, ButtonSetting, HotkeySetting, ComponentSetting } from "@/plugins/core/types"
|
||||
@@ -90,7 +92,10 @@
|
||||
loadPluginSettings();
|
||||
})
|
||||
|
||||
const { showColourPicker } = $props<{ showColourPicker: () => void }>();
|
||||
const { showColourPicker, showDisclaimer } = $props<{
|
||||
showColourPicker: () => void;
|
||||
showDisclaimer: (onConfirm: () => void, onCancel: () => void) => void;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
{#snippet Setting({ title, description, Component, props }: SettingsList) }
|
||||
@@ -222,7 +227,20 @@
|
||||
<div>
|
||||
<Switch
|
||||
state={pluginSettingsValues[plugin.pluginId]?.enabled ?? true}
|
||||
onChange={(value) => updatePluginSetting(plugin.pluginId, 'enabled', value)}
|
||||
onChange={async (value) => {
|
||||
if (plugin.pluginId === 'assessments-average' && value === true) {
|
||||
showDisclaimer(
|
||||
async () => {
|
||||
await updatePluginSetting(plugin.pluginId, 'enabled', true);
|
||||
},
|
||||
() => {
|
||||
// Do nothing on cancel
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
await updatePluginSetting(plugin.pluginId, 'enabled', value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -340,6 +358,25 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-center px-4 py-3">
|
||||
<div class="pr-4">
|
||||
<h2 class="text-sm font-bold">Show Privacy Notification</h2>
|
||||
<p class="text-xs">Show the privacy notification popup on next page load</p>
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
settingsState.privacyStatementShown = false;
|
||||
settingsState.privacyStatementLastUpdated = undefined;
|
||||
closeExtensionPopup();
|
||||
// Small delay to ensure popup is closed before showing notification
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
await showPrivacyNotification();
|
||||
}}
|
||||
text="Show Now"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@ const updatedFirefoxManifest = {
|
||||
},
|
||||
browser_specific_settings: {
|
||||
gecko: {
|
||||
id: pkg.author.email,
|
||||
id: "betterseqta@betterseqta.com",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -8,12 +8,16 @@
|
||||
object-fit: cover;
|
||||
z-index: 4;
|
||||
box-shadow: 0 0 0 3px #000000;
|
||||
transition: box-shadow 0.05s ease-in-out;
|
||||
}
|
||||
|
||||
.dark .userInfoImg {
|
||||
box-shadow: 0 0 0 3px #ffffff;
|
||||
transition: box-shadow 0.05s ease-in-out;
|
||||
}
|
||||
|
||||
.userInfosvgdiv {
|
||||
filter: invert(0) !important;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.userInfoImg {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,14 +147,21 @@ export class ThemeManager {
|
||||
public async initialize(): Promise<void> {
|
||||
console.debug("[ThemeManager] Starting initialization");
|
||||
try {
|
||||
// Check if theme creator was open during reload
|
||||
const neumorphicThemeId = "9a9786d1-b5fc-4a91-8c7a-f8bf7f7679ad";
|
||||
const migrationCSS = "#title {\nbackground: transparent !important;\n}";
|
||||
|
||||
const theme = (await localforage.getItem(neumorphicThemeId)) as CustomTheme | null;
|
||||
if (theme && theme.CustomCSS && !theme.CustomCSS.includes("#title {\nbackground: transparent !important;\n}")) {
|
||||
theme.CustomCSS = theme.CustomCSS + "\n" + migrationCSS;
|
||||
await localforage.setItem(neumorphicThemeId, theme);
|
||||
}
|
||||
|
||||
const themeCreatorOpen = localStorage.getItem("themeCreatorOpen");
|
||||
if (themeCreatorOpen === "true") {
|
||||
console.debug(
|
||||
"[ThemeManager] Theme creator was open, clearing preview state",
|
||||
);
|
||||
this.clearPreview();
|
||||
// Clean up the flag
|
||||
localStorage.removeItem("themeCreatorOpen");
|
||||
}
|
||||
|
||||
|
||||
@@ -23,12 +23,10 @@ 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 { showPrivacyNotification } from "@/seqta/utils/Openers/OpenPrivacyNotification";
|
||||
|
||||
import {
|
||||
updateTimetableTimes,
|
||||
} from "@/seqta/utils/updateTimetableTimes";
|
||||
import { updateTimetableTimes } from "@/seqta/utils/updateTimetableTimes";
|
||||
|
||||
// JSON content
|
||||
import MenuitemSVGKey from "@/seqta/content/MenuItemSVGKey.json";
|
||||
@@ -96,7 +94,12 @@ export async function finishLoad() {
|
||||
console.error("Error during loading cleanup:", err);
|
||||
}
|
||||
|
||||
if (settingsState.justupdated && !document.getElementById("whatsnewbk")) {
|
||||
// Check and show privacy statement notification (before what's new)
|
||||
if (!document.getElementById("privacy-notification")) {
|
||||
await showPrivacyNotification();
|
||||
}
|
||||
|
||||
if (settingsState.justupdated && !document.getElementById("whatsnewbk") && !document.getElementById("privacy-notification")) {
|
||||
OpenWhatsNewPopup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,28 +173,35 @@ async function updateStudentInfo(students: any) {
|
||||
);
|
||||
});
|
||||
|
||||
let houseelement1 = document.getElementsByClassName("userInfohouse")[0];
|
||||
const houseelement = houseelement1 as HTMLElement;
|
||||
const houseelement = document.getElementsByClassName("userInfohouse")[0] as HTMLElement;
|
||||
|
||||
// Fallback to N/A
|
||||
let text = 'N/A';
|
||||
const student = students[index] ?? {};
|
||||
|
||||
// If student has a house, prefer to show year + house. If no year, only show house.
|
||||
if (student.house) {
|
||||
text = `${student.year ?? ""}${student.house}`;
|
||||
|
||||
// If house_colour exists, compute colour
|
||||
if (student.house_colour) {
|
||||
houseelement.style.background = student.house_colour;
|
||||
|
||||
if (students[index]?.house) {
|
||||
if (students[index]?.house_colour) {
|
||||
houseelement.style.background = students[index].house_colour;
|
||||
try {
|
||||
let colorresult = GetThresholdOfColor(students[index]?.house_colour);
|
||||
const colorresult = GetThresholdOfColor(student.house_colour);
|
||||
houseelement.style.color =
|
||||
colorresult && colorresult > 300 ? "black" : "white";
|
||||
houseelement.innerText = students[index].year + students[index].house;
|
||||
} catch (error) {
|
||||
houseelement.innerText = students[index].house;
|
||||
|
||||
} catch (err) {
|
||||
// Colour calculation failed, no text colour set
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
houseelement.innerText = students[index].year;
|
||||
} catch (err) {
|
||||
houseelement.innerText = "N/A";
|
||||
}
|
||||
} else if (student.year) {
|
||||
// No house, only year will be shown
|
||||
text = student.year;
|
||||
}
|
||||
|
||||
houseelement.innerText = text;
|
||||
}
|
||||
|
||||
function createNewsButton(fragment: DocumentFragment, menu: HTMLElement) {
|
||||
|
||||
@@ -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],
|
||||
});
|
||||
}
|
||||
|
||||
+19
-98
@@ -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],
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import stringToHTML from "../stringToHTML";
|
||||
import { settingsState } from "../listeners/SettingsState";
|
||||
import { openPopup } from "./PopupManager";
|
||||
|
||||
export function showPrivacyNotification() {
|
||||
const lastUpdated = "2025-12-19";
|
||||
|
||||
if (document.getElementById("whatsnewbk")) return;
|
||||
if (settingsState.privacyStatementShown) return;
|
||||
if (settingsState.privacyStatementLastUpdated && new Date(settingsState.privacyStatementLastUpdated) > new Date(lastUpdated)) return;
|
||||
|
||||
const header = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
<h1>Privacy Statement</h1>
|
||||
<p>Important Information</p>
|
||||
</div>`,
|
||||
).firstChild as HTMLElement;
|
||||
|
||||
const text = stringToHTML(/* html */ `
|
||||
<div class="whatsnewTextContainer privacyStatement" style="overflow-y: auto; font-size: 1.2rem; line-height: 1.6;">
|
||||
<img style="aspect-ratio: 16/5.8;" 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>
|
||||
<strong>Addressing Recent Concerns About BetterSEQTA+</strong><br>
|
||||
We appreciate the feedback we've received from several schools regarding BetterSEQTA+. Transparency and trust are core to our mission, and we want to address these concerns directly.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Our Commitment to Privacy:</strong><br>
|
||||
<span style="display: block; margin-left: 1em;">
|
||||
• We do not collect, store, or share any personal information<br>
|
||||
• All data processing happens locally on your device<br>
|
||||
• Our code is open source and available for review
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<strong>What We're Doing:</strong><br>
|
||||
We're willing to actively work with school administrators to ensure BetterSEQTA+ meets both student needs and institutional requirements. If your school has specific concerns, we encourage them to contact us at <a href="mailto:betterseqta.plus@gmail.com" style="color: inherit; text-decoration: underline;">betterseqta.plus@gmail.com</a> or via github at <a href="https://github.com/BetterSEQTA/BetterSEQTA-Plus" target="_blank" rel="noopener noreferrer" style="color: inherit; text-decoration: underline;">github.com/BetterSEQTA/BetterSEQTA-Plus</a>.
|
||||
</p>
|
||||
<p>
|
||||
For complete details about our privacy practices, visit our <a href="https://betterseqta.org/privacy" target="_blank" rel="noopener noreferrer" style="color: inherit; text-decoration: underline;">privacy policy</a> or click the shield icon in settings.
|
||||
</p>
|
||||
</div>
|
||||
`).firstChild as HTMLElement;
|
||||
|
||||
settingsState.privacyStatementLastUpdated = "2025-12-20";
|
||||
settingsState.privacyStatementShown = true;
|
||||
|
||||
openPopup({
|
||||
header,
|
||||
content: [text],
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import stringToHTML from "../stringToHTML";
|
||||
import { openPopup } from "./PopupManager";
|
||||
|
||||
export function OpenPrivacyStatement() {
|
||||
const header = stringToHTML(
|
||||
/* html */
|
||||
`<div class="whatsnewHeader">
|
||||
<h1>Privacy Statement</h1>
|
||||
<p>Our commitment to your privacy</p>
|
||||
</div>`,
|
||||
).firstChild as HTMLElement;
|
||||
|
||||
const text = stringToHTML(/* html */ `
|
||||
<div class="whatsnewTextContainer" style="overflow-y: auto; max-height: 60vh;">
|
||||
<h2 style="margin-top: 0;">Privacy Policy</h2>
|
||||
<p>At BetterSEQTA+, we take your privacy seriously. We want to be completely transparent about how we handle your data.</p>
|
||||
|
||||
<h3>Data Collection</h3>
|
||||
<p><strong>We never collect any information from you.</strong> BetterSEQTA+ is designed to work entirely on your device. All processing happens locally in your browser, and we do not send any data to external servers.</p>
|
||||
|
||||
<h3>What We Don't Do</h3>
|
||||
<ul style="text-align: left; margin: 10px 0;">
|
||||
<li>We do not track your browsing activity</li>
|
||||
<li>We do not collect personal information</li>
|
||||
<li>We do not store your SEQTA credentials</li>
|
||||
<li>We do not send data to third-party services</li>
|
||||
<li>We do not use analytics or tracking cookies</li>
|
||||
</ul>
|
||||
|
||||
<h3>Local Storage</h3>
|
||||
<p>BetterSEQTA+ uses your browser's local storage to save your preferences and settings. This data remains on your device and is never transmitted anywhere. You can clear this data at any time through your browser's settings.</p>
|
||||
|
||||
<h3>Open Source</h3>
|
||||
<p>BetterSEQTA+ is an open-source project. You can review our code on <a href="https://github.com/BetterSEQTA/BetterSEQTA-Plus" target="_blank" style="color: inherit; text-decoration: underline;">GitHub</a> to verify our privacy practices. We believe in transparency and encourage you to inspect the code yourself.</p>
|
||||
|
||||
<h3>Our Commitment</h3>
|
||||
<p>We are committed to providing the best features possible while respecting your privacy. We understand that schools and students have concerns about data privacy, and we want to assure you that BetterSEQTA+ is designed with privacy as a core principle.</p>
|
||||
|
||||
<p style="margin-top: 20px; font-weight: bold;">If you have any questions or concerns about our privacy practices, please reach out to us through our <a href="https://github.com/BetterSEQTA/BetterSEQTA-Plus" target="_blank" style="color: inherit; text-decoration: underline;">GitHub repository</a>.</p>
|
||||
</div>
|
||||
`).firstChild as HTMLElement;
|
||||
|
||||
openPopup({
|
||||
header,
|
||||
content: [text],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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,23 @@ 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); */
|
||||
const text = stringToHTML(/* html */ `
|
||||
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: auto;">
|
||||
|
||||
let textcontainer = document.createElement("div");
|
||||
textcontainer.classList.add("whatsnewTextContainer");
|
||||
<h1>3.4.13 - Bug Fixes & Styling Improvements</h1>
|
||||
<li>Fixed house/year box hard failing when house_colour does not exist</li>
|
||||
<li>Fixed message of the day being unreadable in light mode</li>
|
||||
<li>Fixed global font styling issues due to SEQTA updates</li>
|
||||
<li>Fixed styling issues with title bar and other elements</li>
|
||||
<li>Other minor bug fixes and improvements</li>
|
||||
|
||||
let text = stringToHTML(/* html */ `
|
||||
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: scroll;">
|
||||
<h1>3.4.12 - Privacy Updates & Bug Fixes</h1>
|
||||
<li>Added privacy statement</li>
|
||||
<li>Added disclaimer modal to assessment averages switch</li>
|
||||
<li>Improved popup management system</li>
|
||||
<li>Other minor bug fixes and improvements</li>
|
||||
|
||||
<h1>3.4.11 - New Features & Bug Fixes</h1>
|
||||
<li>Added Background Music plugin</li>
|
||||
@@ -133,7 +111,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 +125,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 +142,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 +151,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 +168,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 +187,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 +196,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 +204,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 +299,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],
|
||||
});
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -30,6 +30,8 @@ export interface SettingsState {
|
||||
subjectfilters: Record<string, any>;
|
||||
transparencyEffects: boolean;
|
||||
justupdated?: boolean;
|
||||
privacyStatementShown?: boolean;
|
||||
privacyStatementLastUpdated?: string;
|
||||
timeFormat?: string;
|
||||
animations: boolean;
|
||||
defaultPage: string;
|
||||
|
||||
Reference in New Issue
Block a user