diff --git a/manifest.json b/manifest.json index 76cd2729..033a1a4a 100644 --- a/manifest.json +++ b/manifest.json @@ -20,8 +20,7 @@ "permissions": ["tabs", "notifications", "storage"], "host_permissions": ["https://newsapi.org/", "*://*/*"], "background": { - "service_worker": "src/background.ts", - "type": "module" + "service_worker": "src/background.ts" }, "content_scripts": [ { diff --git a/package.json b/package.json index 9546214c..e85b7dc6 100644 --- a/package.json +++ b/package.json @@ -5,16 +5,8 @@ "description": "BetterSEQTA+ is a browser extension that adds features to SEQTA.", "browserslist": "> 0.5%, last 2 versions, not dead", "scripts": { - "dev": "parcel watch manifest.json --host localhost --config @parcel/config-webextension --no-hmr --no-content-hash", - "dev:firefox": "parcel watch firefox/manifest.json --host localhost --config @parcel/config-webextension --no-hmr --no-content-hash", - - "build": "parcel build manifest.json --config @parcel/config-webextension --no-content-hash --no-cache", - "build:firefox": "parcel build firefox/manifest.json --config @parcel/config-webextension --no-content-hash --no-cache", - - "production": "rimraf ./dist/* && npm-run-all build sentry:sourcemaps sentry:popup-sourcemaps package", - - "sentry:sourcemaps": "sentry-cli sourcemaps inject --org betterseqta-plus --project betterseqtaplus-main ./dist && sentry-cli sourcemaps upload --org betterseqta-plus --project betterseqtaplus-main ./dist", - "sentry:popup-sourcemaps": "sentry-cli sourcemaps inject --org betterseqta-plus --project betterseqtaplus-popup ./dist && sentry-cli sourcemaps upload --org betterseqta-plus --project betterseqtaplus-popup ./dist", + "dev": "vite dev", + "build": "vite build", "package": "rimraf ./dist/*.map && 7z a -tzip extension.zip ./dist/*" }, "targets": { @@ -28,41 +20,40 @@ "author": "", "license": "MIT", "devDependencies": { - "@parcel/config-webextension": "^2.11.0", - "@parcel/optimizer-data-url": "^2.11.0", - "@parcel/packager-ts": "2.11.0", - "@parcel/transformer-inline-string": "^2.11.0", - "@parcel/transformer-sass": "2.12.0", + "@crxjs/vite-plugin": "beta", + "@vitejs/plugin-react-swc": "^3.6.0", "eslint": "^8.56.0", "parcel": "^2.11.0", "prettier": "^3.2.5", "process": "^0.11.10", - "querystring-es3": "^0.2.1", "sass": "^1.70.0", "sass-loader": "^13.3.3", "url": "^0.11.3" }, "dependencies": { - "@parcel/transformer-raw": "^2.11.0", + "@million/lint": "latest", "@sentry/browser": "^7.100.1", "@sentry/cli": "^2.28.6", "@sentry/react": "^7.100.1", + "@sentry/vite-plugin": "^2.16.0", "@types/color": "^3.0.6", "@types/dompurify": "^3.0.5", "@types/react": "^18.2.55", "@types/react-dom": "^18.2.19", "@types/sortablejs": "^1.15.7", "@types/webextension-polyfill": "^0.10.7", + "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.17", "color": "^4.2.3", "dompurify": "^3.0.8", "framer-motion": "^10.18.0", "install": "^0.13.0", "localforage": "^1.10.0", + "million": "latest", "motion": "^10.17.0", "npm": "^10.4.0", "npm-run-all": "^4.1.5", - "postcss": "^8.4.35", + "preact": "^10.20.0", "react": "^18.2.0", "react-best-gradient-color-picker": "^3.0.5", "react-dom": "^18.2.0", @@ -72,6 +63,7 @@ "tailwindcss": "^3.4.1", "ts-loader": "^9.5.1", "typescript": "^5.3.3", + "vite": "^5.2.2", "webextension-polyfill": "^0.10.0" } } diff --git a/src/SEQTA.ts b/src/SEQTA.ts index ed333486..b193fbbe 100644 --- a/src/SEQTA.ts +++ b/src/SEQTA.ts @@ -3,13 +3,11 @@ import * as Sentry from "@sentry/browser"; import { animate, spring, stagger } from 'motion' import loading, { AppendLoadingSymbol } from './seqta/ui/Loading' -import updateVideo from 'url:./resources/update-video.mp4' -import IconFamily from 'url:./resources/fonts/IconFamily.woff' -import LogoLight from 'url:./resources/icons/betterseqta-light-icon.png' -import LogoLightOutline from 'url:./resources/icons/betterseqta-light-outline.png' -import icon48 from 'url:./resources/icons/icon-48.png' - -import Popup from 'url:./interface/index.html' +import updateVideo from './resources/update-video.mp4' +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' import Color from 'color' import MenuitemSVGKey from './seqta/content/MenuItemSVGKey.json' @@ -24,12 +22,14 @@ import browser from 'webextension-polyfill' import coursesicon from './seqta/icons/coursesIcon' import { delay } from "./seqta/utils/delay" import { enableCurrentTheme } from './seqta/ui/Themes' -import * as iframeCSS from "bundle-text:./css/iframe.scss" +import iframeCSSURL from "./css/iframe.scss?raw" import { onError } from './seqta/utils/onError' import stringToHTML from './seqta/utils/stringToHTML' import { updateAllColors } from './seqta/ui/colors/Manager' import { updateBgDurations } from './seqta/ui/Animation' import { SettingsResizer } from "./seqta/ui/SettingsResizer"; +import documentLoadCSS from './css/documentload.scss?inline' +import injectedCSS from './css/injected.scss?inline' declare global { interface Window { @@ -44,6 +44,7 @@ let UserInitalCode = '' let currentSelectedDate = new Date() let LessonInterval: any export let DarkMode: boolean +let iframeCSS: string var MenuItemMutation = false var NonSEQTAPage = false @@ -61,15 +62,25 @@ document.addEventListener( if (hasSEQTAText && hasSEQTATitle && !IsSEQTAPage) { IsSEQTAPage = true console.log('[BetterSEQTA+] Verified SEQTA Page') - import('./css/documentload.scss') - + console.log('[BetterSEQTA+] Injecting CSS') + const documentLoadStyle = document.createElement('style') + documentLoadStyle.textContent = documentLoadCSS + document.head.appendChild(documentLoadStyle) + /* console.log(browser.runtime.getURL(documentLoadCSS)) + console.log(stringToHTML(``)) + document.head.appendChild(stringToHTML(``).firstChild as HTMLLinkElement) + */ enableCurrentTheme() try { const items = await browser.storage.local.get() as SettingsState if (items.onoff) { - import('./css/injected.scss') + const injectedStyle = document.createElement('style') + injectedStyle.textContent = injectedCSS + + document.head.appendChild(injectedStyle) + //document.head.appendChild(stringToHTML(``).firstChild as HTMLLinkElement) } main(items) @@ -136,7 +147,7 @@ export function OpenWhatsNewPopup() { 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', updateVideo) + source.setAttribute('src', browser.runtime.getURL(updateVideo)) source.setAttribute('type', 'video/mp4') video.autoplay = true video.muted = true @@ -428,6 +439,11 @@ function removeThemeTagsFromNotices () { } async function updateIframesWithDarkMode(): Promise { + if (iframeCSS === undefined) { + //iframeCSS = await (await fetch(iframeCSSURL)).text() + iframeCSS = iframeCSSURL + } + // Load the CSS file to overwrite iFrame default CSS const cssLink = document.createElement('style') cssLink.classList.add('iframecss') @@ -819,7 +835,7 @@ function InjectCustomIcons() { style.innerHTML = ` @font-face { font-family: 'IconFamily'; - src: url('${IconFamily}') format('woff'); + src: url('${browser.runtime.getURL(IconFamily)}') format('woff'); font-weight: normal; font-style: normal; }` @@ -906,7 +922,7 @@ function addExtensionSettings() { document.body.appendChild(extensionPopup) const extensionIframe: HTMLIFrameElement = document.createElement('iframe') - extensionIframe.src = `${Popup}#settings/embedded` + extensionIframe.src = `${browser.runtime.getURL('src/interface/index.html')}#settings/embedded` extensionIframe.id = 'ExtensionIframe' extensionIframe.setAttribute('allowTransparency', 'true') extensionIframe.setAttribute('excludeDarkCheck', 'true') @@ -1722,7 +1738,7 @@ function callHomeTimetable(date: string, change?: any) { var dummyDay = document.createElement('div') dummyDay.classList.add('day-empty') let img = document.createElement('img') - img.src = LogoLight + img.src = browser.runtime.getURL(LogoLight) let text = document.createElement('p') text.innerText = 'No lessons available.' dummyDay.append(img) @@ -2275,7 +2291,7 @@ async function loadHomePage() { } const icon = document.querySelector('link[rel*="icon"]')! as HTMLLinkElement - icon.href = icon48 + icon.href = browser.runtime.getURL(icon48) currentSelectedDate = new Date() @@ -2764,7 +2780,7 @@ function SendNewsPage() { articleimage.classList.add('articleimage') if (newsarticles[i].urlToImage == 'null') { - articleimage.style.backgroundImage = `url(${LogoLightOutline})` + articleimage.style.backgroundImage = `url(${browser.runtime.getURL(LogoLightOutline)})` articleimage.style.width = '20%' articleimage.style.margin = '0 7.5%' } else { diff --git a/src/interface/main.tsx b/src/interface/main.tsx index c146b8db..bdbda5b7 100644 --- a/src/interface/main.tsx +++ b/src/interface/main.tsx @@ -5,7 +5,7 @@ import './index.css'; import { SettingsContextProvider } from './SettingsContext.js'; import SettingsPage from './SettingsPage.js'; import browser from 'webextension-polyfill'; -import font from 'url:../resources/fonts/IconFamily.woff' +import font from '../resources/fonts/IconFamily.woff' import * as Sentry from "@sentry/react"; @@ -26,7 +26,7 @@ style.setAttribute("type", "text/css"); style.innerHTML = ` @font-face { font-family: 'IconFamily'; - src: url('${font}') format('woff'); + src: url('${browser.runtime.getURL(font)}') format('woff'); font-weight: normal; font-style: normal; }`; diff --git a/src/seqta/ui/ImageBackgrounds.ts b/src/seqta/ui/ImageBackgrounds.ts index d9cde539..218ede48 100644 --- a/src/seqta/ui/ImageBackgrounds.ts +++ b/src/seqta/ui/ImageBackgrounds.ts @@ -1,4 +1,3 @@ -import backgroundPage from 'url:./background/background.html' import browser from 'webextension-polyfill'; import { SettingsState } from '../../types/storage'; @@ -14,6 +13,6 @@ export async function appendBackgroundToUI() { background.id = 'background'; background.classList.add('imageBackground'); background.setAttribute('excludeDarkCheck', 'true'); - background.src = backgroundPage; + background.src = browser.runtime.getURL('src/seqta/ui/background/background.html'); parent!.appendChild(background); } diff --git a/src/seqta/ui/colors/Manager.ts b/src/seqta/ui/colors/Manager.ts index a8c68782..25719450 100644 --- a/src/seqta/ui/colors/Manager.ts +++ b/src/seqta/ui/colors/Manager.ts @@ -4,8 +4,8 @@ import { lightenAndPaleColor } from './lightenAndPaleColor'; import ColorLuminance from './ColorLuminance'; import { SettingsState } from '../../../types/storage'; -import darkLogo from 'url:../../../resources/icons/betterseqta-light-full.png'; -import lightLogo from 'url:../../../resources/icons/betterseqta-dark-full.png'; +import darkLogo from '../../../resources/icons/betterseqta-light-full.png'; +import lightLogo from '../../../resources/icons/betterseqta-dark-full.png'; // Helper functions const setCSSVar = (varName: any, value: any) => document.documentElement.style.setProperty(varName, value); @@ -39,10 +39,10 @@ export function updateAllColors(storedSetting: any, newColor = null) { let modeProps = {}; if (DarkMode !== null) { modeProps = DarkMode ? { - '--betterseqta-logo': `url(${darkLogo})` + '--betterseqta-logo': `url(${browser.runtime.getURL(darkLogo)})` } : { '--better-pale': lightenAndPaleColor(selectedColor), - '--betterseqta-logo': `url(${lightLogo})` + '--betterseqta-logo': `url(${browser.runtime.getURL(lightLogo)})` }; if (DarkMode) { diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 00000000..895cfae6 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from 'vite' +import { crx } from '@crxjs/vite-plugin' +import million from "million/compiler" +import manifest from './manifest.json' +import react from '@vitejs/plugin-react-swc' +import { sentryVitePlugin } from "@sentry/vite-plugin"; + +export default defineConfig({ + plugins: [ + react(), + million.vite({}), + crx({ manifest }), + sentryVitePlugin({ + org: process.env.SENTRY_ORG, + project: 'betterseqtaplus-main', + authToken: process.env.SENTRY_AUTH_TOKEN, + }), + sentryVitePlugin({ + org: process.env.SENTRY_ORG, + project: 'betterseqtaplus-popup', + authToken: process.env.SENTRY_AUTH_TOKEN, + }), + ], +})