Compare commits

..

51 Commits

Author SHA1 Message Date
sethburkart123 f996e4bf19 bump: version to hotfix 2024-08-28 15:05:05 +10:00
sethburkart123 30c5a823d8 fix: assessments not loading after notices error #150 2024-08-28 15:02:09 +10:00
sethburkart123 10977247cc fix: manifest description too long 2024-08-27 17:39:26 +10:00
sethburkart123 cd4dc73897 clean: remove excess permissions 2024-08-27 17:14:09 +10:00
sethburkart123 d748eece8a update: add tab icon to changelog 2024-08-27 16:52:40 +10:00
sethburkart123 37dab0f5a7 fix: background script matchmedia broken 2024-08-27 16:51:28 +10:00
sethburkart123 842a132c7f fix: ReadME.md heading image not working 2024-08-26 23:43:47 +10:00
sethburkart123 b36426a94b clean: fix up readMe formatting 2024-08-26 23:42:49 +10:00
Seth Burkart 9659f9aae2 Update README.md 2024-08-26 23:33:59 +10:00
sethburkart123 b205c0f832 feat: update whats new content 2024-08-26 23:28:57 +10:00
sethburkart123 f99e76c723 fix: ReadME.md heading image not working 2024-08-26 23:26:58 +10:00
Seth Burkart 4680e9879d fix: readme banner not showing properly 2024-08-26 23:26:16 +10:00
Seth Burkart cfdea6a116 chore: Update README.md 2024-08-26 23:24:10 +10:00
sethburkart123 31954dcbce feat: change update video to webm format 2024-08-26 23:22:12 +10:00
sethburkart123 444cb14e8a feat: switch to github for update video 2024-08-26 23:21:24 +10:00
sethburkart123 856ef62306 fix: theme locking sometimes falling out of sync 2024-08-26 23:03:22 +10:00
sethburkart123 5335bba04c chore: update what's new with latest changes 2024-08-25 18:59:02 +10:00
sethburkart123 611fcef12b feat: add help to theme creator 2024-08-25 13:39:52 +10:00
sethburkart123 6e4fe64789 feat: add theme idea button on store to encourage sharing 2024-08-25 09:33:05 +10:00
sethburkart123 545a999c46 fix: direct messages lacking right padding 2024-08-25 09:01:30 +10:00
sethburkart123 b6dbcfeb69 style: slight changes to store cards 2024-08-25 08:58:45 +10:00
sethburkart123 5bc3d22214 style: improve look of store cards 2024-08-25 08:43:47 +10:00
sethburkart123 be44e86290 fix: theme switching broken on popup 2024-08-25 06:18:58 +10:00
sethburkart123 a78993fffc fix: remove broken import 2024-08-25 06:17:17 +10:00
sethburkart123 a8ff2213bd clean: remove unnecessary logs 2024-08-24 20:45:46 +10:00
sethburkart123 7519312282 fix: theme locking not working in light mode 2024-08-24 20:45:02 +10:00
sethburkart123 8b9ad39e8e style: add consistent styling for the notices home page container 2024-08-23 13:54:06 +10:00
sethburkart123 182597efce fix: settings ui not following animations setting 2024-08-21 21:20:30 +10:00
sethburkart123 4d38af402f fix: respect prefers reduced motion by default 2024-08-21 21:10:52 +10:00
sethburkart123 e19020066a style: improve look of popovers 2024-08-21 20:47:34 +10:00
sethburkart123 ee76b4d9d2 clean: remove unnecessary important css rules 2024-08-21 20:44:25 +10:00
sethburkart123 47014bc77f style: improve direct message iframe styling 2024-08-21 18:37:56 +10:00
sethburkart123 3dc7396f7a fix: arrow disappearing on dropdowns in direct messages 2024-08-21 18:26:31 +10:00
sethburkart123 f70c032f06 fix: force dark mode on theme editing 2024-08-21 17:44:27 +10:00
sethburkart123 5d97ab3da6 fix: lock dark mode toggle with theme settings 2024-08-21 17:36:21 +10:00
Seth Burkart 5549de571d Fix: README.md - outdated folders 2024-08-21 16:04:43 +10:00
Seth Burkart 8bad8d5b34 Merge pull request #148 from ar-cyber/patch-2
fix grammatical errors and missing features
2024-08-21 14:35:43 +10:00
Andrew R f97276082e fix grammatical errors and missing features 2024-08-21 13:11:11 +09:30
sethburkart123 4a9048ac62 feat: add force theme option to custom themes 2024-08-20 12:57:07 +10:00
sethburkart123 a2dac4d84d style: improve file theming 2024-08-16 10:30:26 +10:00
sethburkart123 ddd1bbe847 fix: animations sometimes not activating instantly causing 'glitching' 2024-08-16 10:26:15 +10:00
sethburkart123 0873a33da2 fix: Inefficient regular expression #147 2024-08-14 16:15:11 +10:00
sethburkart123 f9c2f5876f chore: clean up SEQTA.ts imports 2024-08-14 16:12:49 +10:00
Seth Burkart dfef312ddc Merge pull request #146 from OMGerCoder/main
Update URL validity check to support port numbers
2024-08-05 14:37:12 +10:00
OMGerCoder 629c98ce0e Update URL validity check to support port numbers 2024-08-05 12:43:48 +09:30
sethburkart123 3279775a99 fix: iframes not changing to light mode correctly in some cases 2024-07-30 16:46:06 +10:00
sethburkart123 97089e5134 fix: remove incorrectly called function 2024-07-30 16:19:02 +10:00
sethburkart123 fed198108a fix: light dark labels inverted 2024-07-30 16:17:24 +10:00
Seth Burkart 76ed27e82d Merge pull request #141 from 97-42/main
Update README.md
2024-07-30 07:00:20 +10:00
97-42 cc88d8c984 Update README.md 2024-07-29 17:40:57 +08:00
Alphons Joseph c6b4bdcbc9 Always track latest version of contribute.md 2024-07-27 15:33:46 +08:00
28 changed files with 309 additions and 302 deletions
+30 -14
View File
@@ -11,30 +11,36 @@
<a target="_blank" href="https://discord.gg/YzmbnCDkat"><img src="https://github.com/SethBurkart123/EvenBetterSEQTA/assets/108050083/23055730-b16e-44c0-9bef-221d8545af92" width="240" style="border-radius:10%;" /></a>
</p>
## Table of contents
- [Features](#features)
- [Getting Started](#getting-started)
## Release Videos
<video autoplay loop muted controls="false" width="33%" src="https://github.com/SethBurkart123/EvenBetterSEQTA/assets/108050083/3084644a-edbc-40e5-b1ad-1fdea4f0ca18"></video>
<div>
<img src="https://img.shields.io/chrome-web-store/users/afdgaoaclhkhemfkkkonemoapeinchel" />
<img src="https://img.shields.io/chrome-web-store/rating/afdgaoaclhkhemfkkkonemoapeinchel" />
</div>
## Table of contents
- [Features](#features)
- [Creating Custom Themes](#creating-custom-themes)
- [Getting Started](#getting-started)
- [Running Development](#running-development)
- [Building for production](#building-for-production)
- [Folder Structure](#folder-structure)
- [Contributors](#contributors)
- [Credits](#credits)
- [Star History](#star-history)
## Features
- Dark mode
- Custom Background
- Custom Background/Themes
- Improved Styling/CSS
- Improved look for SEQTA Learn
- Custom Home Page including:
- Daily Lessons
- Shortcuts
- Easier Access Notices
- Assessments
- Options to remove certain items from the side menu
- Fully customisable themes and an offical theme store
- Notification for next lesson (sent 5 minutes before end of the lesson)
- Browser Support
- Chrome Supported
@@ -42,9 +48,21 @@
- Brave Supported
- Opera Supported
- Vivaldi Supported
- Firefox (Experimental - available [here](https://addons.mozilla.org/en-US/firefox/addon/betterseqta-plus/))
- Firefox (Experimental - available [here](https://addons.mozilla.org/en-US/firefox/addon/betterseqta-plus/)
- Safari (Experimental - only available via compilation)
## Creating Custom Themes
If you are looking to create custom themes, I would recommend you start at the official documentation [here](https://betterseqta.gitbook.io/betterseqta-docs). You can see some premade examples along with a compilation script that can be used to allow for CSS frameworks and libraries such as SCSS to be used [here](https://github.com/SethBurkart123/BetterSEQTA-theme-generator).
Don't worry- if you get stuck feel free to ask around in the discord. We're open and happy to help out! Happy creating :)
## Creating Custom Themes
If you are looking to create custom themes, I would recommend you start at the official documentation [here](https://betterseqta.gitbook.io/betterseqta-docs). You can see some premade examples along with a compilation script that can be used to allow for CSS frameworks and libraries such as SCSS to be used [here](https://github.com/SethBurkart123/BetterSEQTA-theme-generator).
Don't worry- if you get stuck feel free to ask around in the discord. We're open and happy to help out! Happy creating :)
## Getting started
1. Clone the repository
@@ -93,7 +111,7 @@ npm run build
3. Package it up (optional)
```
npm run package # this requires 7zip to be installed in order to work
npm run package # This requires 7-Zip to be installed in order to work
```
## Folder Structure
@@ -106,15 +124,13 @@ The folder structure is as follows:
- The `dist` folder is where the compiled code ends up, this is the folder what you need to load into chrome as an unpacked extension for development.
- The `safari` folder is an Xcode project, building it for MacOS does work, IOS needs a few modifications to the manifest to work, but I have managed to get it working. It will give an error, to fix this you need to regenerate it, you can delete the safari folder and then run the command `xcrun safari-web-extension-converter <extension-folder>/dist` and it will automatically generate the xcode project where you are.
## Contributors
<a href="https://github.com/betterseqta/betterseqta-plus/graphs/contributors">
<img src="https://contrib.rocks/image?repo=betterseqta/betterseqta-plus" />
</a>
Want to contribute? [Click Here!](https://github.com/BetterSEQTA/BetterSEQTA-Plus/contribute.md)
Want to contribute? [Click Here!](https://github.com/BetterSEQTA/BetterSEQTA-Plus/blob/main/contribute.md)
## Credits
This extension was initially developed by [Nulkem](https://github.com/Nulkem/betterseqta), was ported to manifest V3 by [MEGA-Dawg68](https://github.com/MEGA-Dawg68) and is currently under active development by [SethBurkart123](https://github.com/SethBurkart123) and [Crazypersonalph](https://github.com/Crazypersonalph)
+1 -1
View File
@@ -17,7 +17,7 @@
"64": "src/resources/icons/icon-64.png"
}
},
"permissions": ["tabs", "notifications", "storage", "activeTab", "scripting"],
"permissions": ["tabs", "notifications", "storage", "activeTab"],
"host_permissions": ["<all_urls>"],
"background": {
"scripts": ["src/background.ts"]
+3 -3
View File
@@ -1,8 +1,8 @@
{
"manifest_version": 3,
"name": "BetterSEQTA+",
"version": "3.3.0",
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development, and incorporate a plethora of new features!",
"version": "3.3.1",
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development add add heaps more features!",
"icons": {
"32": "src/resources/icons/icon-32.png",
"48": "src/resources/icons/icon-48.png",
@@ -17,7 +17,7 @@
"64": "src/resources/icons/icon-64.png"
}
},
"permissions": ["tabs", "notifications", "storage", "scripting"],
"permissions": ["tabs", "notifications", "storage"],
"host_permissions": ["https://newsapi.org/", "*://*/*"],
"background": {
"service_worker": "src/background.ts"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "betterseqtaplus",
"version": "3.2.6",
"version": "3.3.0",
"type": "module",
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development, and incorporate a plethora of new features!",
"browserslist": "> 0.5%, last 2 versions, not dead",
+110 -61
View File
@@ -1,32 +1,40 @@
// Third-party libraries
import Color from 'color'
import Sortable from 'sortablejs'
import browser from 'webextension-polyfill'
import { animate, spring, stagger } from 'motion'
import loading, { AppendLoadingSymbol } from './seqta/ui/Loading'
// Internal utilities and functions
import { delay } from './seqta/utils/delay'
import stringToHTML from './seqta/utils/stringToHTML'
import { MessageHandler } from './seqta/utils/listeners/MessageListener'
import { initializeSettingsState, settingsState } from './seqta/utils/listeners/SettingsState'
import { StorageChangeHandler } from './seqta/utils/listeners/StorageChanges'
import { eventManager } from './seqta/utils/listeners/EventManager'
// UI and theme management
import loading, { AppendLoadingSymbol } from './seqta/ui/Loading'
import { enableCurrentTheme } from './seqta/ui/themes/enableCurrent'
import { updateAllColors } from './seqta/ui/colors/Manager'
import { SettingsResizer } from './seqta/ui/SettingsResizer'
import { AddBetterSEQTAElements } from './seqta/ui/AddBetterSEQTAElements'
// JSON content
import MenuitemSVGKey from './seqta/content/MenuItemSVGKey.json'
import ShortcutLinks from './seqta/content/links.json'
// Icons and fonts
import IconFamily from './resources/fonts/IconFamily.woff'
import LogoLight from './resources/icons/betterseqta-light-icon.png'
import LogoLightOutline from './resources/icons/betterseqta-light-outline.png'
import icon48 from './resources/icons/icon-48.png?base64'
import Color from 'color'
import MenuitemSVGKey from './seqta/content/MenuItemSVGKey.json'
import { MessageHandler } from './seqta/utils/listeners/MessageListener'
import ShortcutLinks from './seqta/content/links.json'
import Sortable from 'sortablejs'
import assessmentsicon from './seqta/icons/assessmentsIcon'
import browser from 'webextension-polyfill'
import coursesicon from './seqta/icons/coursesIcon'
import { delay } from "./seqta/utils/delay"
import { enableCurrentTheme } from "./seqta/ui/themes/enableCurrent";
import iframeCSS from "./css/iframe.scss?raw"
// Stylesheets
import iframeCSS from './css/iframe.scss?raw'
import injectedCSS from './css/injected.scss?inline'
import stringToHTML from './seqta/utils/stringToHTML'
import { updateAllColors } from './seqta/ui/colors/Manager'
import { SettingsResizer } from "./seqta/ui/SettingsResizer";
import documentLoadCSS from './css/documentload.scss?inline'
import { injectYouTubeVideo } from './seqta/ui/VideoLoader'
import { initializeSettingsState, settingsState } from './seqta/utils/listeners/SettingsState'
import { StorageChangeHandler } from './seqta/utils/listeners/StorageChanges'
import { AddBetterSEQTAElements } from './seqta/ui/AddBetterSEQTAElements'
import { eventManager } from './seqta/utils/listeners/EventManager'
declare global {
interface Window {
@@ -133,9 +141,16 @@ export function OpenWhatsNewPopup() {
let imagecont = document.createElement('div')
imagecont.classList.add('whatsnewImgContainer')
let div = document.createElement('div')
div.classList.add('whatsnewImg')
imagecont.appendChild(div)
let video = document.createElement('video')
let source = document.createElement('source')
// Perhaps we host this on a server and then grab it instead of having it locally?
source.setAttribute('src', 'https://raw.githubusercontent.com/BetterSEQTA/BetterSEQTA-Plus/main/src/resources/update-video.webm')
video.autoplay = true
video.muted = true
video.loop = true
video.appendChild(source)
video.classList.add('whatsnewImg')
imagecont.appendChild(video)
let textcontainer = document.createElement('div')
textcontainer.classList.add('whatsnewTextContainer')
@@ -143,9 +158,23 @@ export function OpenWhatsNewPopup() {
let text = stringToHTML(
/* html */ `
<div class="whatsnewTextContainer" style="height: 50%;overflow-y: scroll;">
<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>Find and create awesome themes! <span style="background: var(--background-secondary); color: var(--text-primary); padding: 2px 4px; border-radius: 4px; font-size: 12px; font-weight: 600;">Beta</span></li>
<li>Added a theme store!</li>
<li>Added the new theme creator!</li>
<li>Fixed Notices not working on home page</li>
<li>Fixed dark/light button labels inverted</li>
<li>Switched to GitHub for hosting the update video</li>
<li>Fixed an issue where the settings menu wouldn't change theme</li>
<li>Fixed custom shortcuts not allowing ports to be used</li>
<li>Fixed occasional flashing when using animations</li>
<li>Fixed loading of the tab icon</li>
<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>
@@ -285,10 +314,6 @@ export function OpenWhatsNewPopup() {
let bkelement = document.getElementById('whatsnewbk')
let popup = document.getElementsByClassName('whatsnewContainer')[0]
injectYouTubeVideo(
'JdDA45GYEUc', 'PLSlFV-9e6dvyvZJFPCtBMb3LSp-LGbrbI', document.querySelector('.whatsnewImg')!, true, true, '100%', '100%'
)
if (settingsState.animations) {
animate(
[popup, bkelement as HTMLElement],
@@ -484,7 +509,7 @@ async function updateIframesWithDarkMode(): Promise<void> {
}, (element) => {
const iframe = element as HTMLIFrameElement;
try {
applyDarkModeToIframe(iframe, cssLink, settingsState.DarkMode);
applyDarkModeToIframe(iframe, cssLink);
if (element.classList.contains('cke_wysiwyg_frame')) {
(async () => {
@@ -498,18 +523,20 @@ async function updateIframesWithDarkMode(): Promise<void> {
});
}
function applyDarkModeToIframe(iframe: HTMLIFrameElement, cssLink: HTMLStyleElement, DarkMode: boolean): void {
function applyDarkModeToIframe(iframe: HTMLIFrameElement, cssLink: HTMLStyleElement): void {
const iframeDocument = iframe.contentDocument;
if (!iframeDocument) return;
if (iframeDocument.readyState !== 'complete') {
iframe.onload = () => {
applyDarkModeToIframe(iframe, cssLink, DarkMode);
applyDarkModeToIframe(iframe, cssLink);
};
return;
}
if (DarkMode) iframeDocument.documentElement.classList.add('dark');
if (settingsState.DarkMode) {
iframeDocument.documentElement.classList.add('dark')
}
const head = iframeDocument.head;
if (head && !head.innerHTML.includes('iframecss')) {
@@ -603,10 +630,15 @@ async function handleSublink(sublink: string | undefined): Promise<void> {
handleMessages(document.querySelector('.messages')!)
await handleDefault()
break;
default:
await handleDefault();
case 'dashboard':
handleDashboard(document.querySelector('.dashboard')!)
await handleDefault()
break;
}
default:
await handleDefault()
break;
}
}
async function handleTimetable(): Promise<void> {
@@ -649,6 +681,12 @@ async function handleMessages(node: Element): Promise<void> {
if (!settingsState.animations) return;
// Hides messages on page load
const style = document.createElement('style')
style.classList.add('messageHider')
style.innerHTML = '[data-message]{opacity: 0 !important;}'
document.head.append(style)
await waitForElm('[data-message]', true, 10);
const messages = Array.from(document.querySelectorAll('[data-message]')).slice(0, 35);
animate(
@@ -660,12 +698,19 @@ async function handleMessages(node: Element): Promise<void> {
easing: [.22, .03, .26, 1]
}
);
document.head.querySelector('style.messageHider')?.remove()
}
async function handleDashboard(node: Element): Promise<void> {
if (!(node instanceof HTMLElement)) return;
if (!settingsState.animations) return;
const style = document.createElement('style')
style.classList.add('dashboardHider')
style.innerHTML = '.dashboard{opacity: 0 !important;}'
document.head.append(style)
await waitForElm('.dashlet', true, 10);
animate(
'.dashboard > *',
@@ -676,6 +721,8 @@ async function handleDashboard(node: Element): Promise<void> {
easing: [.22, .03, .26, 1]
}
);
document.head.querySelector('style.dashboardHider')?.remove()
}
async function handleDocuments(node: Element): Promise<void> {
@@ -2150,7 +2197,7 @@ export async function loadHomePage() {
var Notices = stringToHTML(NoticesStr)
// Appends the shortcut container into the home container
document.getElementById('home-container')!.append(Notices.firstChild!)
document.getElementById('home-container')!.append(Notices.firstChild!) // HERE!!!
if (settingsState.animations) {
animate(
@@ -2174,38 +2221,41 @@ export async function loadHomePage() {
const response = await GetPrefs.json()
const labelArray = response.payload.filter((item: any) => item.name === 'notices.filters').map((item: any) => item.value)[0].split(' ')
const labelArray = response.payload.filter((item: any) => item.name === 'notices.filters').map((item: any) => item.value)
const xhr2 = new XMLHttpRequest()
xhr2.open(
'POST',
`${location.origin}/seqta/student/load/notices?`,
true
)
xhr2.setRequestHeader('Content-Type', 'application/json; charset=utf-8')
xhr2.onreadystatechange = function () {
if (xhr2.readyState === 4) {
processNotices(xhr2.response, labelArray);
}
};
const dateControl = document.querySelector('input[type="date"]') as HTMLInputElement;
xhr2.send(JSON.stringify({ date: dateControl.value }));
function onInputChange(e: any) {
xhr2.open('POST', `${location.origin}/seqta/student/load/notices?`, true);
xhr2.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr2.send(JSON.stringify({ date: e.target.value }));
if (labelArray.length !== 0) {
const labelArray = response.payload.filter((item: any) => item.name === 'notices.filters').map((item: any) => item.value)[0].split(' ')
const xhr2 = new XMLHttpRequest()
xhr2.open(
'POST',
`${location.origin}/seqta/student/load/notices?`,
true
)
xhr2.setRequestHeader('Content-Type', 'application/json; charset=utf-8')
xhr2.onreadystatechange = function () {
if (xhr2.readyState === 4) {
processNotices(xhr2.response, labelArray);
}
};
}
dateControl.addEventListener('input', onInputChange);
const dateControl = document.querySelector('input[type="date"]') as HTMLInputElement;
xhr2.send(JSON.stringify({ date: dateControl.value }));
function onInputChange(e: any) {
xhr2.open('POST', `${location.origin}/seqta/student/load/notices?`, true);
xhr2.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr2.send(JSON.stringify({ date: e.target.value }));
xhr2.onreadystatechange = function () {
if (xhr2.readyState === 4) {
processNotices(xhr2.response, labelArray);
}
};
}
dateControl.addEventListener('input', onInputChange);
}
if (settingsState.notificationcollector) {
enableNotificationCollector()
@@ -2280,8 +2330,7 @@ function processNotices(responseText: any, labelArray: any) {
let colour = notice.colour;
if (typeof colour === 'string') {
const rgb = GetThresholdOfColor(colour);
const DarkModeResult = settingsState.DarkMode;
if (rgb < 100 && DarkModeResult) {
if (rgb < 100 && settingsState.DarkMode) {
colour = undefined;
}
}
+1 -11
View File
@@ -1,6 +1,5 @@
import browser from 'webextension-polyfill'
import { SettingsState } from "./types/storage";
import { applyYoutubeStyles } from './seqta/ui/VideoLoader';
export const openDB = () => {
return new Promise((resolve, reject) => {
@@ -118,16 +117,6 @@ browser.runtime.onMessage.addListener((request: any, _sender: any, sendResponse:
GetNews(sendResponse, url);
return true;
case 'youtubeIframe':
const { hideControls } = request;
browser.scripting.executeScript({
target: { tabId: _sender.tab.id, allFrames: true },
func: applyYoutubeStyles,
args: [hideControls]
});
break;
default:
console.log('Unknown request type');
}
@@ -283,6 +272,7 @@ async function UpdateCurrentValues() {
browser.runtime.onInstalled.addListener(function (event) {
browser.storage.local.remove(['justupdated']);
browser.storage.local.remove(['data']);
UpdateCurrentValues();
if ( event.reason == 'install', event.reason == 'update' ) {
browser.storage.local.set({ justupdated: true });
+36 -37
View File
@@ -159,7 +159,13 @@ html {
color: white;
}
.legacy-root button:active, .legacy-root a:active {
.cke_panel {
border-radius: 16px !important;
margin-top: 8px !important;
background: unset;
}
.legacy-root button:active, .legacy-root a:active:not(.cke_combo_button) {
background-image: unset !important;
}
@@ -543,13 +549,13 @@ td.colourBar {
}
#toolbar .search {
padding-left: 30px;
/* Provides space for the icon */
}
#toolbar span:has(.search)::before {
content: "\eca5";
/* Unicode for the search icon */
position: absolute;
left: 8px;
z-index: 10;
top: 50%;
transform: translateY(-50%);
color: currentColor;
@@ -616,10 +622,6 @@ ul.buttonChecklist {
margin-right: auto;
overflow: visible;
}
ol > [data-message] {
padding-left: 8px !important;
padding-right: 4px !important;
}
ol > [data-label] {
margin-left: 4px;
margin-bottom: 4px;
@@ -1035,6 +1037,7 @@ div > ol:has(.uiFileHandlerWrapper) {
overflow-y: auto;
display: flex;
flex-direction: column;
border-radius: 16px;
border-bottom-left-radius: 15px;
border-bottom-right-radius: 15px;
}
@@ -1050,11 +1053,9 @@ div > ol:has(.uiFileHandlerWrapper) {
}
.notice {
position: relative;
width: 95%;
padding: 20px;
display: flex;
flex-direction: column;
margin: 0px auto 7px;
background: var(--background-primary);
transition: 200ms;
box-shadow: inset 0px 5px 20px 1px rgba(0, 0, 0, 0.3);
@@ -1454,11 +1455,6 @@ div > ol:has(.uiFileHandlerWrapper) {
height: 180px;
background: var(--background-primary);
}
.cke_panel {
border-radius: 16px;
overflow: hidden;
background: unset;
}
.Avatar__Avatar___gE5kx.Avatar__staff___4gVLs {
--person-colour: var(--better-light);
background: var(--person-colour, var(--navy));
@@ -1571,7 +1567,7 @@ div,
ol,
ul {
scrollbar-width: thin !important;
scrollbar-color: var(--better-light) var(--better-sub) !important;
scrollbar-color: var(--better-light) var(--better-sub);
}
.connectedNotificationsWrapper > div > button {
color: var(--text-primary) !important;
@@ -1656,6 +1652,22 @@ ul {
.MenuButton__MenuPanel___2q42B {
background: var(--background-primary);
color: var(--text-primary);
border-radius: 16px;
overflow: clip;
> div {
padding: 0 !important;
display: flex;
flex-direction: column;
gap: 4px;
> div {
> h2 {
padding-bottom: 1px;
padding-left: 12px;
}
}
}
}
.dailycal > .header {
color: var(--text-primary);
@@ -1718,6 +1730,11 @@ div.entry.class[style*="width: 46.5%"] {
margin-top: 4px !important;
}
.uiFile {
border-radius: 8px !important;
transition: all 0.2s ease-in-out;
}
.dark .title a.uiFile {
color: #06b4fc !important;
}
@@ -1869,13 +1886,15 @@ div.bar.flat {
padding: 0;
}
.cke_toolbox {
padding: 0 !important;
padding-left: 8px !important;
background: unset !important;
gap: 4px;
gap: 0 8px;
}
.cke_toolbox > .cke_toolbar > .cke_toolgroup {
margin: 0;
margin: 0 !important;
}
#cke_1_top a:hover {
#cke_1_top a:hover:not(.cke_combo_button) {
background: #5a5a5a;
}
.legacy-root button.depressed,
@@ -2884,32 +2903,12 @@ li.MessageList__unread___3imtO {
padding-bottom: 16px;
}
.whatsnewImg {
background-color: black;
pointer-events: none !important;
margin: 8px auto;
width: 90%;
border-radius: 16px;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.3);
}
.whatsnewImg > iframe {
aspect-ratio: 16/9.823;
width: 100%;
height: 100%;
border-radius: 16px;
opacity: 0;
animation: fade-in 0.5s forwards;
animation-delay: 0.8s !important;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.whatsnewTextContainer {
display: flex;
overflow-x: hidden;
+2 -1
View File
@@ -25,7 +25,8 @@ export const SettingsContextProvider: React.FC<{ children: ReactNode }> = ({ chi
transparencyEffects: false,
selectedTheme: '',
animations: true,
defaultPage: 'home'
defaultPage: 'home',
devMode: false
});
const [showPicker, setShowPicker] = useState<boolean>(false);
+19 -19
View File
@@ -1,32 +1,32 @@
import React, { memo, useEffect, useRef, useState } from 'react';
import { motion } from 'framer-motion';
import type { TabbedContainerProps } from '../types/TabbedContainerProps';
import { useSettingsContext } from '../SettingsContext';
const TabbedContainer: React.FC<TabbedContainerProps> = ({ tabs }) => {
const { settingsState } = useSettingsContext();
const [activeTab, setActiveTab] = useState(0);
const [hoveredTab, setHoveredTab] = useState<number | null>(null);
const [tabWidth, setTabWidth] = useState(0);
const [position, setPosition] = useState(0);
const positionRef = useRef(position);
// Function to handle message
const handleMessage = (event: MessageEvent) => {
if (event.data === "popupClosed") {
setActiveTab(0);
}
};
// Function to handle message
const handleMessage = (event: MessageEvent) => {
if (event.data === "popupClosed") {
setActiveTab(0);
}
useEffect(() => {
// Add event listener for 'message' event
window.addEventListener("message", handleMessage);
// Cleanup
return () => {
window.removeEventListener("message", handleMessage);
};
useEffect(() => {
// Add event listener for 'message' event
window.addEventListener("message", handleMessage);
// Cleanup
return () => {
window.removeEventListener("message", handleMessage);
};
}, []);
}, []);
useEffect(() => {
const newPosition = -activeTab * 100;
@@ -36,7 +36,7 @@ const TabbedContainer: React.FC<TabbedContainerProps> = ({ tabs }) => {
const containerRef = useRef(null);
const springTransition = { type: 'spring', stiffness: 250, damping: 25 };
const springTransition = settingsState.animations ? { type: 'spring', stiffness: 250, damping: 25 } : { duration: 0 };
useEffect(() => {
if (containerRef.current) {
@@ -85,8 +85,8 @@ const TabbedContainer: React.FC<TabbedContainerProps> = ({ tabs }) => {
className='flex'
>
{tabs.map((tab, index) => (
<div key={index} className={`absolute h-[100vh] focus-visible:outline-none overflow-y-scroll w-full pb-40 transition-opacity duration-300 ${activeTab === index ? 'opacity-100' : 'opacity-0'}`}
style={{left: `${index * 100}%`}}>
<div key={index} className={`absolute h-[100vh] focus-visible:outline-none overflow-y-scroll w-full pb-40 ${ settingsState.animations ? 'transition-opacity duration-300' : ''} ${activeTab === index ? 'opacity-100' : 'opacity-0'}`}
style={{left: `${index * 100}%`}}>
{tab.content}
</div>
))}
+2 -2
View File
@@ -53,9 +53,9 @@ const useSettingsState = ({ settingsState, setSettingsState }: SettingsProps) =>
for (const [key, { newValue }] of Object.entries(changes)) {
if (key === "DarkMode") {
if (key === "DarkMode" && newValue) {
document.body.classList.add('dark');
document.documentElement.classList.add('dark');
} else {
document.body.classList.remove('dark');
document.documentElement.classList.remove('dark');
}
}
+4 -4
View File
@@ -35,11 +35,11 @@ root.render(
<div className="grid w-full h-screen text-center place-content-center dark:text-white">
<h1 className="text-2xl font-bold">An error occurred 😭😭😭</h1>
<p className="text-lg">Try clicking this button and see if it helps...</p>
<button className='flex gap-2 p-2 px-4 mx-auto mt-4 text-white rounded-lg bg-zinc-100 dark:bg-zinc-800/20 outline outline-white/20 w-fit' onClick={() => window.location.reload()}>
<button className='flex gap-2 p-2 px-4 mx-auto mt-4 rounded-lg dark:text-white bg-zinc-100 dark:bg-zinc-800/20 outline outline-white/20 w-fit' onClick={() => window.location.reload()}>
<svg height="18" width="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg">
<g fill="#F7F7F7">
<path d="M9.03,12.22c-.293-.293-.768-.293-1.061,0s-.293,.768,0,1.061l1.208,1.208c-.059,.002-.118,.012-.178,.012-3.032,0-5.5-2.467-5.5-5.5,0-1.616,.706-3.143,1.938-4.191,.315-.269,.354-.742,.085-1.057s-.74-.353-1.058-.085c-1.567,1.333-2.466,3.277-2.466,5.333,0,3.76,2.983,6.829,6.704,6.985l-.735,.735c-.293,.293-.293,.768,0,1.061,.146,.146,.338,.22,.53,.22s.384-.073,.53-.22l2.25-2.25c.293-.293,.293-.768,0-1.061l-2.25-2.25Z" fill="#F7F7F7"/>
<path d="M9.296,2.015l.735-.735c.293-.293,.293-.768,0-1.061s-.768-.293-1.061,0l-2.25,2.25c-.293,.293-.293,.768,0,1.061l2.25,2.25c.146,.146,.338,.22,.53,.22s.384-.073,.53-.22c.293-.293,.293-.768,0-1.061l-1.208-1.208c.059-.002,.118-.012,.177-.012,3.032,0,5.5,2.467,5.5,5.5,0,1.616-.706,3.143-1.938,4.191-.315,.269-.354,.742-.085,1.057,.148,.174,.359,.264,.571,.264,.172,0,.345-.059,.486-.179,1.567-1.333,2.466-3.277,2.466-5.333,0-3.76-2.983-6.829-6.704-6.985Z" fill="#F7F7F7"/>
<g fill="currentColor">
<path d="M9.03,12.22c-.293-.293-.768-.293-1.061,0s-.293,.768,0,1.061l1.208,1.208c-.059,.002-.118,.012-.178,.012-3.032,0-5.5-2.467-5.5-5.5,0-1.616,.706-3.143,1.938-4.191,.315-.269,.354-.742,.085-1.057s-.74-.353-1.058-.085c-1.567,1.333-2.466,3.277-2.466,5.333,0,3.76,2.983,6.829,6.704,6.985l-.735,.735c-.293,.293-.293,.768,0,1.061,.146,.146,.338,.22,.53,.22s.384-.073,.53-.22l2.25-2.25c.293-.293,.293-.768,0-1.061l-2.25-2.25Z" fill="currentColor"/>
<path d="M9.296,2.015l.735-.735c.293-.293,.293-.768,0-1.061s-.768-.293-1.061,0l-2.25,2.25c-.293,.293-.293,.768,0,1.061l2.25,2.25c.146,.146,.338,.22,.53,.22s.384-.073,.53-.22c.293-.293,.293-.768,0-1.061l-1.208-1.208c.059-.002,.118-.012,.177-.012,3.032,0,5.5,2.467,5.5,5.5,0,1.616-.706,3.143-1.938,4.191-.315,.269-.354,.742-.085,1.057,.148,.174,.359,.264,.571,.264,.172,0,.345-.059,.486-.179,1.567-1.333,2.466-3.277,2.466-5.333,0-3.76-2.983-6.829-6.704-6.985Z" fill="currentColor"/>
</g>
</svg>
Reload
+1 -1
View File
@@ -41,7 +41,7 @@ const SettingsPage = ({ standalone }: SettingsPage) => {
<button onClick={() => browser.runtime.sendMessage({ type: 'currentTab', info: 'OpenChangelog' })} className="absolute w-8 h-8 text-lg rounded-xl font-IconFamily top-1 right-1 bg-zinc-100 dark:bg-zinc-700"></button>
</div>
<Picker />
<TabbedContainer tabs={tabs} />
<TabbedContainer tabs={tabs} animations={false} />
</div>
</SettingsContextProvider>
);
@@ -28,7 +28,7 @@ const Shortcuts = memo(() => {
const isValidTitle = useCallback((title: string) => title.trim() !== "", []);
const isValidURL = useCallback((url: string) => {
const pattern = new RegExp("^(https?:\\/\\/)?[\\w.-]+[\\w.-]+(/[\\w.-]*)*$", "i");
const pattern = new RegExp("^(https?:\\/\\/)?[\\w.-]+(?:\\.[\\w\\-]+)*(?::\\d+)?(/[\\w\\-./]*)*$", "i");
return pattern.test(url);
}, []);
+18 -49
View File
@@ -201,7 +201,7 @@ const Store = () => {
>
<motion.div
onClick={(e) => e.stopPropagation()}
className="w-full max-w-xl h-[95%] p-8 pt-5 bg-white rounded-t-2xl dark:bg-zinc-800 overflow-scroll"
className="w-full max-w-xl h-[95%] p-4 bg-white rounded-t-2xl dark:bg-zinc-800 overflow-scroll"
exit={{ y: "100vh" }}
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
variants={containerVariants}
@@ -219,7 +219,7 @@ const Store = () => {
<motion.h2 className="mb-4 text-2xl font-bold" variants={textVariants}>
{displayTheme.name}
</motion.h2>
<motion.img src={displayTheme.coverImage} alt="Theme Cover" className="object-cover w-full mb-4 rounded-md" variants={textVariants} />
<motion.img src={displayTheme.marqueeImage} alt="Theme Cover" className="object-cover w-full mb-4 rounded-md" variants={textVariants} />
<motion.p className="mb-4 text-gray-700 dark:text-gray-300" variants={textVariants}>
{displayTheme.description}
</motion.p>
@@ -259,16 +259,9 @@ const Store = () => {
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
{gridThemes.filter(theme => theme.id !== displayTheme.id).sort((a, b) => a.name.localeCompare(displayTheme.name) - b.name.localeCompare(displayTheme.name)).map((theme, index) => (
<motion.div key={index} onClick={() => { setDisplayTheme(null); setDisplayTheme(theme); }} className='w-full cursor-pointer' variants={textVariants}>
<div
className="w-full overflow-clip rounded-xl transition-all duration-300 relative group/card flex flex-col hover:shadow-xl dark:hover:shadow-white/[0.1] hover:shadow-white/[0.8] h-auto"
>
<div className='absolute bottom-0 left-0 z-10 p-2'>
<h6 className="text-xl font-bold text-neutral-600 dark:text-white">
{theme.name}
</h6>
<p className="max-w-sm text-sm text-neutral-500 dark:text-neutral-200">
{theme.description}
</p>
<div className="bg-gray-50 w-full transition-all hover:scale-105 duration-500 relative group group/card flex flex-col hover:shadow-2xl dark:hover:shadow-white/[0.1] hover:shadow-white/[0.8] dark:bg-zinc-800 dark:border-white/[0.1] h-auto rounded-xl overflow-clip border">
<div className="absolute z-10 mb-1 text-xl font-bold text-white transition-all duration-500 group-hover:-translate-y-0.5 bottom-1 left-3">
{theme.name}
</div>
<div className='absolute bottom-0 z-0 w-full h-3/4 bg-gradient-to-t from-black/80 to-transparent' />
<img src={theme.coverImage} alt="Theme Preview" className="object-cover w-full h-48" />
@@ -304,52 +297,28 @@ const Store = () => {
<div className="grid grid-cols-1 gap-4 py-12 mx-auto sm:grid-cols-2 lg:grid-cols-3">
{filteredThemes.map((theme, index) => (
<div onClick={() => setDisplayTheme(theme)} key={index} className='w-full cursor-pointer'>
<div className="bg-gray-50 w-full transition-all duration-300 relative group/card flex flex-col hover:shadow-2xl dark:hover:shadow-white/[0.1] hover:shadow-white/[0.8] dark:bg-zinc-800 dark:border-white/[0.1] h-auto rounded-xl p-6 border">
<div>
<div className="mb-1 text-xl font-bold text-neutral-600 dark:text-white">
{theme.name}
</div>
<p className="max-w-sm mb-4 text-sm text-neutral-500 dark:text-neutral-300">
{theme.description}
</p>
<div className="bg-gray-50 w-full transition-all hover:scale-105 duration-500 relative group group/card flex flex-col hover:shadow-2xl dark:hover:shadow-white/[0.1] hover:shadow-white/[0.8] dark:bg-zinc-800 dark:border-white/[0.1] h-auto rounded-xl overflow-clip border">
<div className="absolute z-10 mb-1 text-xl font-bold text-white transition-all duration-500 group-hover:-translate-y-0.5 bottom-1 left-3">
{theme.name}
</div>
<div className='absolute bottom-0 z-0 w-full h-3/4 bg-gradient-to-t from-black/80 to-transparent' />
<div
className='w-full'>
<img src={theme.coverImage} alt="Theme Preview" className="object-cover w-full h-48 rounded-md" />
</div>
<div>
{
currentThemes.includes(theme.id) ?
<button
onClick={() => removeTheme(theme.id)}
className="flex px-4 py-2 mt-4 ml-auto transition rounded-full dark:text-white bg-zinc-300 dark:bg-zinc-700 dark:hover:bg-zinc-600/50 hover:bg-zinc-200 focus:outline-none focus:ring-2 focus:ring-zinc-800 focus:ring-offset-2">
{ installingThemes.includes(theme.id) ?
<>
<SpinnerIcon className="w-4 h-4 mr-2" />
Removing...
</> :
<> Remove </>
}
</button> :
<button
onClick={() => downloadTheme(theme.id)}
className="flex px-4 py-2 mt-4 ml-auto transition rounded-full dark:text-white bg-zinc-300 dark:bg-zinc-700 dark:hover:bg-zinc-600/50 hover:bg-zinc-200 focus:outline-none focus:ring-2 focus:ring-zinc-800 focus:ring-offset-2">
{ installingThemes.includes(theme.id) ?
<>
<SpinnerIcon className="w-4 h-4 mr-2" />
Installing...
</> :
<> Install </>
}
</button>
}
</div>
</div>
</div>
))}
<a href="https://betterseqta.gitbook.io/betterseqta-docs" className='w-full cursor-pointer'>
<div className="bg-zinc-50 h-48 w-full transition-all hover:scale-105 duration-500 relative justify-center items-center group group/card flex flex-col hover:shadow-2xl dark:hover:shadow-white/[0.1] hover:shadow-white/[0.8] dark:bg-zinc-800 dark:border-white/[0.1] rounded-xl overflow-clip border">
<div className="text-2xl font-IconFamily">{'\uecb3'}</div>
<div className="text-xl font-bold text-center transition-all duration-500 dark:text-white">
Got a Theme Idea?
<p className="text-lg font-light subtitle">Transform it into a stunning theme!</p>
</div>
</div>
</a>
</div>
{filteredThemes.length == 0 && !loading && (
<div className="flex flex-col items-center justify-center w-full text-center h-96">
+31 -1
View File
@@ -4,7 +4,7 @@ import ColorPicker from 'react-best-gradient-color-picker';
import Accordion from '../components/Accordian';
import Switch from '../components/Switch';
import { sendThemeUpdate } from '../hooks/ThemeManagment';
import { PlusIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { MoonIcon, PlusIcon, SunIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { v4 as uuidv4 } from 'uuid';
import { CustomTheme, CustomThemeBase64 } from '../types/CustomThemes';
import browser from 'webextension-polyfill';
@@ -23,6 +23,7 @@ function ThemeCreator() {
coverImage: null,
isEditable: true,
hideThemeName: false,
forceDark: undefined,
});
useEffect(() => {
@@ -159,6 +160,12 @@ function ThemeCreator() {
<div className='w-full min-h-[100vh] bg-zinc-100 dark:bg-zinc-800 dark:text-white transition duration-30'>
<div className='flex flex-col p-2'>
<h1 className='text-xl font-semibold'>Theme Creator</h1>
<a href="https://betterseqta.gitbook.io/betterseqta-docs" target="_blank" className='text-sm font-light text-zinc-500 dark:text-zinc-400'>
<span className="no-underline font-IconFamily pr-0.5">{'\ueb44'}</span>
<span className="underline">
Need help? Check out the docs!
</span>
</a>
<Divider />
@@ -244,6 +251,29 @@ function ThemeCreator() {
<Divider /> */}
<div className='flex items-center justify-between'>
<div>
<div className='pr-2 text-sm font-semibold'>Force Theme</div>
<div className='pr-2 text-[11px]'>Force users to use either dark or light mode</div>
</div>
<Switch state={theme.forceDark == undefined ? false : true} onChange={value => setTheme({ ...theme, forceDark: value ? false : undefined })} />
</div>
{ theme.forceDark != undefined &&
<div className='flex items-center justify-between pt-4'>
<div>
<div className='pr-2 text-sm font-semibold'>Force {theme.forceDark ? 'Dark' : 'Light'} Mode</div>
<div className='pr-2 text-[11px]'>Force users to use {theme.forceDark ? 'dark' : 'light'} mode</div>
</div>
<button className='flex items-center justify-center p-2 transition rounded-lg bg-zinc-100 dark:bg-zinc-700' onClick={() => setTheme({ ...theme, forceDark: !theme.forceDark })}>
{theme.forceDark ? <MoonIcon className='w-6 h-6' /> : <SunIcon className='w-6 h-6' />}
</button>
</div>
}
<Divider />
<Accordion defaultOpened title='Default Theme Colour'>
<div className='p-2 mt-2 bg-white rounded-lg w-fit dark:bg-zinc-900'>
<ColorPicker
+1
View File
@@ -12,6 +12,7 @@ export type CustomTheme = {
hideThemeName: boolean;
webURL?: string;
selectedColor?: string;
forceDark?: boolean;
}
export type DownloadedTheme = CustomTheme & {
@@ -5,6 +5,7 @@ export interface Tab {
}
export interface TabbedContainerProps {
tabs: Tab[];
animations?: boolean;
}
declare const TabbedContainer: React.FC<TabbedContainerProps>;
export default TabbedContainer;
Binary file not shown.
Binary file not shown.
+17 -5
View File
@@ -4,6 +4,7 @@ import { appendBackgroundToUI } from "./ImageBackgrounds";
import stringToHTML from "../utils/stringToHTML";
import { settingsState } from "../utils/listeners/SettingsState";
import { updateAllColors } from "./colors/Manager";
import { delay } from "../utils/delay";
export async function AddBetterSEQTAElements() {
if (settingsState.onoff) {
@@ -220,8 +221,8 @@ async function createSettingsButton() {
ContentDiv!.append(SettingsButton.firstChild!);
}
function GetLightDarkModeString(darkMode: boolean) {
if (darkMode) {
function GetLightDarkModeString() {
if (settingsState.DarkMode) {
return 'Switch to light theme'
} else {
return 'Switch to dark theme'
@@ -229,7 +230,7 @@ function GetLightDarkModeString(darkMode: boolean) {
}
async function addDarkLightToggle() {
const tooltipString = GetLightDarkModeString(settingsState.DarkMode);
const tooltipString = GetLightDarkModeString();
const svgContent = settingsState.DarkMode ?
/* html */`<defs><clipPath id="__lottie_element_80"><rect width="24" height="24" x="0" y="0"></rect></clipPath></defs><g clip-path="url(#__lottie_element_80)"><g style="display: block;" transform="matrix(1,0,0,1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,-4 C-2.2100000381469727,-4 -4,-2.2100000381469727 -4,0 C-4,2.2100000381469727 -2.2100000381469727,4 0,4 C2.2100000381469727,4 4,2.2100000381469727 4,0 C4,-2.2100000381469727 2.2100000381469727,-4 0,-4z"></path></g></g><g style="display: block;" transform="matrix(1,0,0,1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,6 C-3.309999942779541,6 -6,3.309999942779541 -6,0 C-6,-3.309999942779541 -3.309999942779541,-6 0,-6 C3.309999942779541,-6 6,-3.309999942779541 6,0 C6,3.309999942779541 3.309999942779541,6 0,6z M8,-3.309999942779541 C8,-3.309999942779541 8,-8 8,-8 C8,-8 3.309999942779541,-8 3.309999942779541,-8 C3.309999942779541,-8 0,-11.3100004196167 0,-11.3100004196167 C0,-11.3100004196167 -3.309999942779541,-8 -3.309999942779541,-8 C-3.309999942779541,-8 -8,-8 -8,-8 C-8,-8 -8,-3.309999942779541 -8,-3.309999942779541 C-8,-3.309999942779541 -11.3100004196167,0 -11.3100004196167,0 C-11.3100004196167,0 -8,3.309999942779541 -8,3.309999942779541 C-8,3.309999942779541 -8,8 -8,8 C-8,8 -3.309999942779541,8 -3.309999942779541,8 C-3.309999942779541,8 0,11.3100004196167 0,11.3100004196167 C0,11.3100004196167 3.309999942779541,8 3.309999942779541,8 C3.309999942779541,8 8,8 8,8 C8,8 8,3.309999942779541 8,3.309999942779541 C8,3.309999942779541 11.3100004196167,0 11.3100004196167,0 C11.3100004196167,0 8,-3.309999942779541 8,-3.309999942779541z"></path></g></g></g>` :
/* html */`<defs><clipPath id="__lottie_element_263"><rect width="24" height="24" x="0" y="0"></rect></clipPath></defs><g clip-path="url(#__lottie_element_263)"><g style="display: block;" transform="matrix(1.5,0,0,1.5,7,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,-4 C-2.2100000381469727,-4 -1.2920000553131104,-2.2100000381469727 -1.2920000553131104,0 C-1.2920000553131104,2.2100000381469727 -2.2100000381469727,4 0,4 C2.2100000381469727,4 4,2.2100000381469727 4,0 C4,-2.2100000381469727 2.2100000381469727,-4 0,-4z"></path></g></g><g style="display: block;" transform="matrix(-1,0,0,-1,12,12)" opacity="1"><g opacity="1" transform="matrix(1,0,0,1,0,0)"><path fill-opacity="1" d=" M0,6 C-3.309999942779541,6 -6,3.309999942779541 -6,0 C-6,-3.309999942779541 -3.309999942779541,-6 0,-6 C3.309999942779541,-6 6,-3.309999942779541 6,0 C6,3.309999942779541 3.309999942779541,6 0,6z M8,-3.309999942779541 C8,-3.309999942779541 8,-8 8,-8 C8,-8 3.309999942779541,-8 3.309999942779541,-8 C3.309999942779541,-8 0,-11.3100004196167 0,-11.3100004196167 C0,-11.3100004196167 -3.309999942779541,-8 -3.309999942779541,-8 C-3.309999942779541,-8 -8,-8 -8,-8 C-8,-8 -8,-3.309999942779541 -8,-3.309999942779541 C-8,-3.309999942779541 -11.3100004196167,0 -11.3100004196167,0 C-11.3100004196167,0 -8,3.309999942779541 -8,3.309999942779541 C-8,3.309999942779541 -8,8 -8,8 C-8,8 -3.309999942779541,8 -3.309999942779541,8 C-3.309999942779541,8 0,11.3100004196167 0,11.3100004196167 C0,11.3100004196167 3.309999942779541,8 3.309999942779541,8 C3.309999942779541,8 8,8 8,8 C8,8 8,3.309999942779541 8,3.309999942779541 C8,3.309999942779541 11.3100004196167,0 11.3100004196167,0 C11.3100004196167,0 8,-3.309999942779541 8,-3.309999942779541z"></path></g></g></g>`;
@@ -247,12 +248,23 @@ async function addDarkLightToggle() {
updateAllColors();
document.getElementById('LightDarkModeButton')!.addEventListener('click', async () => {
const darklightText = document.getElementById('darklighttooliptext');
if (settingsState.originalDarkMode != undefined && settingsState.selectedTheme) {
darklightText!.innerText = 'Locked by current theme';
await delay(1000)
darklightText!.innerText = GetLightDarkModeString();
return
}
settingsState.DarkMode = !settingsState.DarkMode;
updateAllColors();
const darklightText = document.getElementById('darklighttooliptext');
darklightText!.innerText = GetLightDarkModeString(!settingsState.DarkMode);
darklightText!.innerText = GetLightDarkModeString();
});
}
-80
View File
@@ -1,80 +0,0 @@
import Browser from "webextension-polyfill";
/**
* Injects a YouTube iframe into the specified element.
*
* @param videoId - The YouTube video ID to embed.
* @param playlistId - The YouTube playlist ID to allow embed to loop.
* @param mountElement - The element to mount the iframe to.
* @param hideControls - Whether to hide the YouTube player controls.
* @param mute - Whether to mute the video.
* @param width - The width of the iframe.
* @param height - The height of the iframe.
*/
export function injectYouTubeVideo(videoId: string, playlistId: string, mountElement: HTMLElement, hideControls: boolean, mute: boolean, width: string, height: string): void {
const controlsParam = hideControls ? 'controls=0' : 'controls=1';
const autoplayParam = 'autoplay=1';
const muteParam = mute ? 'mute=1' : 'mute=0';
const listParams = playlistId ? `list=${playlistId}&` : '';
const iframeSrc = `https://www.youtube.com/embed/${videoId}?${listParams}${autoplayParam}&${controlsParam}&${muteParam}&loop=1`;
const iframe = document.createElement('iframe');
iframe.width = width;
iframe.height = height;
iframe.src = iframeSrc;
iframe.frameBorder = '0';
iframe.allow = 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture';
iframe.allowFullscreen = true;
iframe.onload = () => {
Browser.runtime.sendMessage({ type: 'youtubeIframe', hideControls });
};
mountElement.innerHTML = ''; // Clear any existing content
mountElement.appendChild(iframe);
/* if (hideControls) {
applyCustomStylesToIframe(iframe);
} */
}
/**
* Function to inject CSS styles into the iframe.
*
* @param hideControls - Whether to hide the YouTube player controls.
*/
export function applyYoutubeStyles(hideControls: boolean) {
if (window.location == window.parent.location) return;
if (!window.location.href.includes('youtube.com/embed/')) return;
if (hideControls) {
const hideControlsCss = `
.ytp-gradient-top,
.ytp-chrome-bottom,
.ytp-chrome-top,
.ytp-chrome-top-buttons,
.ytp-pause-overlay,
.ytp-watermark {
display: none !important;
}
`;
const hideControlsStyle = document.createElement('style');
hideControlsStyle.textContent = hideControlsCss;
document.head.appendChild(hideControlsStyle);
const f =() => {
const btn = document.querySelector('.ytp-ad-skip-button') as HTMLButtonElement | null;
const adText = document.querySelector('.ytp-ad-text');
const v = document.querySelector('video')!;
if(adText){
v.currentTime = v.duration
}
if(btn){
v.currentTime = v.duration
btn.click();
}
}
setInterval(f, 100);
}
}
+2 -2
View File
@@ -64,9 +64,9 @@ export function updateAllColors() {
}
if (settingsState.DarkMode) {
element.contentDocument?.body.classList.add('dark');
element.contentDocument?.documentElement.classList.add('dark');
} else {
element.contentDocument?.body.classList.remove('dark');
element.contentDocument?.documentElement.classList.remove('dark');
}
}
}
@@ -6,6 +6,14 @@ import { settingsState } from '../../utils/listeners/SettingsState';
export const UpdateThemePreview = async (updatedTheme: CustomThemeBase64 /* Omit<CustomTheme, 'CustomImages'> & { CustomImages: Omit<CustomImage, 'blob'>[] } */) => {
const { CustomCSS, CustomImages, defaultColour } = updatedTheme;
if (updatedTheme.forceDark != undefined) {
if (updatedTheme.forceDark) {
settingsState.DarkMode = true;
} else {
settingsState.DarkMode = false;
}
}
// Update image data
const currentImageIds = Object.keys(imageData);
const updatedImageIds = CustomImages.map((image) => image.id);
+7 -1
View File
@@ -1,13 +1,19 @@
import { CustomImage, CustomTheme } from '../../../interface/types/CustomThemes';
import { settingsState } from '../../utils/listeners/SettingsState';
import { applyCustomCSS } from './Themes';
export const applyTheme = async (theme: CustomTheme) => {
export const applyTheme = async (theme: CustomTheme, reEnable?: boolean) => {
let CustomCSS = '';
let CustomImages: CustomImage[] = [];
if (theme?.CustomCSS) CustomCSS = theme.CustomCSS;
if (theme?.CustomImages) CustomImages = theme.CustomImages;
if (theme?.forceDark != undefined) {
if (!reEnable) settingsState.originalDarkMode = settingsState.DarkMode
settingsState.DarkMode = theme.forceDark
}
// Apply custom CSS
applyCustomCSS(CustomCSS);
+1 -1
View File
@@ -8,7 +8,7 @@ export const enableCurrentTheme = async () => {
if (settingsState.selectedTheme) {
const theme = await localforage.getItem(settingsState.selectedTheme) as CustomTheme;
if (theme) {
await applyTheme(theme);
await applyTheme(theme, true);
}
}
};
+5
View File
@@ -20,6 +20,11 @@ export const removeTheme = async (theme: CustomTheme) => {
settingsState.selectedColor = settingsState.originalSelectedColor
}
if (settingsState.originalDarkMode !== undefined) {
settingsState.DarkMode = settingsState.originalDarkMode
settingsState.originalDarkMode = undefined
}
// Remove custom images
const customImageVariables = theme.CustomImages.map((image) => image.variableName);
customImageVariables.forEach((variableName) => {
@@ -21,7 +21,6 @@ class StorageManager {
return Reflect.get(target.data, prop);
},
set: (target, prop: keyof SettingsState, value) => {
console.log(target)
Reflect.set(target.data, prop, value);
target.saveToStorage();
return true;
+1
View File
@@ -37,6 +37,7 @@ export interface SettingsState {
animations: boolean;
defaultPage: string;
devMode?: boolean;
originalDarkMode?: boolean;
}
interface ToggleItem {