mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
refac: improve multi browser support
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
# Copy this file to .env.submit and fill in the values as you wish to publish
|
||||||
|
CHROME_EXTENSION_ID=
|
||||||
|
CHROME_CLIENT_ID=
|
||||||
|
CHROME_CLIENT_SECRET=
|
||||||
|
CHROME_REFRESH_TOKEN=
|
||||||
|
CHROME_PUBLISH_TARGET=
|
||||||
|
CHROME_SKIP_SUBMIT_REVIEW=
|
||||||
|
FIREFOX_EXTENSION_ID=
|
||||||
|
FIREFOX_JWT_ISSUER=
|
||||||
|
FIREFOX_JWT_SECRET=
|
||||||
|
FIREFOX_CHANNEL=
|
||||||
|
EDGE_PRODUCT_ID=
|
||||||
|
EDGE_CLIENT_ID=
|
||||||
|
EDGE_CLIENT_SECRET=
|
||||||
|
EDGE_ACCESS_TOKEN_URL=
|
||||||
|
EDGE_SKIP_SUBMIT_REVIEW= # true or false
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
name: MVP - make, version & publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch: # This line adds manual triggering from the GitHub UI
|
||||||
|
|
||||||
|
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
make_version_publish:
|
||||||
|
name: Make, Version & Publish
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node 20.x
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20.x
|
||||||
|
|
||||||
|
- name: Install bun & Deps
|
||||||
|
run: |
|
||||||
|
npm install bun -g
|
||||||
|
bun install
|
||||||
|
|
||||||
|
- name: 'Build - all browsers'
|
||||||
|
id: buildProject
|
||||||
|
run: MODE=chrome vite build && MODE=firefox vite build
|
||||||
|
|
||||||
|
- name: '[ V E R S I O N ] : Create or Update Release Pull Request - Version Changes'
|
||||||
|
id: changesets
|
||||||
|
uses: changesets/action@v1
|
||||||
|
with:
|
||||||
|
version: bun run version
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: 'Get current version info from package.json'
|
||||||
|
if: steps.changesets.outputs.hasChangesets == 'false'
|
||||||
|
id: package
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=PACKAGE_NAME::$(jq -r .name package.json)"
|
||||||
|
echo "::set-output name=PACKAGE_VERSION::$(jq -r .version package.json)"
|
||||||
|
working-directory: ${{ github.workspace }}
|
||||||
|
|
||||||
|
- name: 'Check if a git release already exists for current version'
|
||||||
|
if: steps.changesets.outputs.hasChangesets == 'false'
|
||||||
|
id: checkRelease
|
||||||
|
run: |
|
||||||
|
TAG_NAME=${{ steps.package.outputs.PACKAGE_NAME }}@${{ steps.package.outputs.PACKAGE_VERSION }}
|
||||||
|
if gh release view $TAG_NAME &>/dev/null; then
|
||||||
|
echo "Release $TAG_NAME already exists."
|
||||||
|
echo "RELEASE_EXISTS=true" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "RELEASE_EXISTS=false" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 'Create Release Archive(s) - zip 🫰 it 🫰 up 🫰 !'
|
||||||
|
id: zip
|
||||||
|
if: steps.changesets.outputs.hasChangesets == 'false'
|
||||||
|
run: bun run zip
|
||||||
|
|
||||||
|
- name: 'Create a git release w/ notes & release archive(s)'
|
||||||
|
id: gitRelease
|
||||||
|
if: steps.changesets.outputs.hasChangesets == 'false' && env.RELEASE_EXISTS != 'true'
|
||||||
|
run: bun run release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PACKAGE_NAME: ${{ steps.package.outputs.PACKAGE_NAME }}
|
||||||
|
PACKAGE_VERSION: ${{ steps.package.outputs.PACKAGE_VERSION }}
|
||||||
+2
-11
@@ -7,24 +7,15 @@ yarn.lock
|
|||||||
|
|
||||||
.parcel-cache
|
.parcel-cache
|
||||||
.env
|
.env
|
||||||
|
.env.submit
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
extension.zip
|
extension.zip
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
|
betterseqtaplus-safari/
|
||||||
|
|
||||||
.million/
|
.million/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
# Sentry Config File
|
|
||||||
.env.sentry-build-plugin
|
|
||||||
|
|
||||||
# Sentry Config File
|
|
||||||
.env.sentry-build-plugin
|
|
||||||
|
|
||||||
# Sentry Config File
|
|
||||||
.env.sentry-build-plugin
|
|
||||||
|
|
||||||
# Sentry Config File
|
|
||||||
.sentryclirc
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import fs from "fs";
|
||||||
|
import mime from "mime-types";
|
||||||
|
|
||||||
|
export const base64Loader = {
|
||||||
|
name: "base64-loader",
|
||||||
|
transform(_: any, id: string) {
|
||||||
|
const [filePath, query] = id.split("?");
|
||||||
|
if (query !== "base64") return null;
|
||||||
|
|
||||||
|
const data = fs.readFileSync(filePath, { encoding: 'base64' });
|
||||||
|
const mimeType = mime.lookup(filePath);
|
||||||
|
const dataURL = `data:${mimeType};base64,${data}`;
|
||||||
|
|
||||||
|
return `export default '${dataURL}';`;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import type { Browser, BuildTarget, Manifest } from './types'
|
||||||
|
import type { AnyCase } from './utils'
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {Manifest} manifest
|
||||||
|
* @param {AnyCase<Browser>} browser
|
||||||
|
* @return {*} {@link BuildTarget}
|
||||||
|
*/
|
||||||
|
export function createManifest(
|
||||||
|
manifest: Manifest,
|
||||||
|
browser: AnyCase<Browser>,
|
||||||
|
): BuildTarget {
|
||||||
|
return {
|
||||||
|
manifest,
|
||||||
|
browser,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a base Manifest to inherit from
|
||||||
|
* type Manifest = chrome.runtime.ManifestV3
|
||||||
|
*
|
||||||
|
* use as shared base to extend inBrowser manifests
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @param {Manifest} manifest
|
||||||
|
* @return {*} {@link Manifest}
|
||||||
|
*/
|
||||||
|
export function createManifestBase(manifest: Manifest): Manifest {
|
||||||
|
return manifest
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
const glob = require('glob');
|
||||||
|
const semver = require('semver');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function getLatestVersion(files) {
|
||||||
|
console.log('Files passed to getLatestVersion:', files);
|
||||||
|
const versions = files.map(file => {
|
||||||
|
const match = file.match(/@(\d+\.\d+\.\d+)-/);
|
||||||
|
console.log('Matching file:', file, 'Version found:', match ? match[1] : 'None');
|
||||||
|
return match ? match[1] : null;
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
console.log('Extracted versions:', versions);
|
||||||
|
const latestVersion = semver.maxSatisfying(versions, '*');
|
||||||
|
console.log('Latest version:', latestVersion);
|
||||||
|
return latestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLatestFiles(browser) {
|
||||||
|
const pattern = `dist/betterseqtaplus@*-*${browser}.zip`;
|
||||||
|
console.log('Glob pattern:', pattern);
|
||||||
|
const files = glob.sync(pattern);
|
||||||
|
console.log('Files found for browser', browser, ':', files);
|
||||||
|
const latestVersion = getLatestVersion(files);
|
||||||
|
|
||||||
|
const latestFile = files.find(file => file.includes(latestVersion));
|
||||||
|
console.log('Latest file for browser', browser, ':', latestFile);
|
||||||
|
return latestFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
function zipSources() {
|
||||||
|
const zipFileName = `dist/betterseqtaplus@latest-sources.zip`;
|
||||||
|
|
||||||
|
const excludePatterns = [
|
||||||
|
'node_modules',
|
||||||
|
'dist',
|
||||||
|
'.env*',
|
||||||
|
'.git',
|
||||||
|
'.github',
|
||||||
|
'.vscode',
|
||||||
|
'LICENSE',
|
||||||
|
'package.json'
|
||||||
|
].map(pattern => `-x!${pattern}`).join(' ');
|
||||||
|
|
||||||
|
const zipCommand = `7z a ${zipFileName} . ${excludePatterns}`;
|
||||||
|
|
||||||
|
console.log('Zipping project sources with command:', zipCommand);
|
||||||
|
execSync(zipCommand, { stdio: 'inherit' });
|
||||||
|
|
||||||
|
return zipFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runPublishCommand(browsers) {
|
||||||
|
const chromeZip = browsers.includes('chrome') ? getLatestFiles('chrome') : null;
|
||||||
|
const firefoxZip = browsers.includes('firefox') ? getLatestFiles('firefox') : null;
|
||||||
|
const firefoxSourcesZip = browsers.includes('firefox') ? zipSources() : null;
|
||||||
|
|
||||||
|
console.log('Chrome zip:', chromeZip);
|
||||||
|
console.log('Firefox zip:', firefoxZip);
|
||||||
|
console.log('Firefox sources zip:', firefoxSourcesZip);
|
||||||
|
|
||||||
|
if (browsers.length === 0) {
|
||||||
|
console.log('No browsers specified. Exiting.');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((browsers.includes('chrome') && !chromeZip) || (browsers.includes('firefox') && (!firefoxZip || !firefoxSourcesZip))) {
|
||||||
|
console.error('Could not find required zip files for specified browsers.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let command = 'publish-extension';
|
||||||
|
if (chromeZip) {
|
||||||
|
command += ` --chrome-zip ${chromeZip}`;
|
||||||
|
}
|
||||||
|
if (firefoxZip && firefoxSourcesZip) {
|
||||||
|
command += ` --firefox-zip ${firefoxZip} --firefox-sources-zip ${firefoxSourcesZip}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Running command:', command);
|
||||||
|
execSync(command, { stdio: 'inherit' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse command-line arguments
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const browserIndex = args.indexOf('--b');
|
||||||
|
const browsers = browserIndex !== -1 ? args.slice(browserIndex + 1) : [];
|
||||||
|
|
||||||
|
runPublishCommand(browsers);
|
||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
import type { ManifestV3Export } from '@crxjs/vite-plugin'
|
||||||
|
import { type AnyCase, createEnum } from './utils'
|
||||||
|
|
||||||
|
export const FrameworkEnum = {
|
||||||
|
React: 'React',
|
||||||
|
Vanilla: 'Vanilla',
|
||||||
|
Preact: 'Preact',
|
||||||
|
Lit: 'Lit',
|
||||||
|
Svelte: 'Svelte',
|
||||||
|
Vue: 'Vue',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const BrowserEnum = {
|
||||||
|
Chrome: 'Chrome',
|
||||||
|
Brave: 'Brave',
|
||||||
|
Opera: 'Opera',
|
||||||
|
Edge: 'Edge',
|
||||||
|
Firefox: 'Firefox',
|
||||||
|
Safari: 'Safari',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
const LanguageEnum = {
|
||||||
|
TypeScript: 'TypeScript',
|
||||||
|
JavaScript: 'JavaScript',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const StyleEnum = {
|
||||||
|
Tailwind: 'Tailwind',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const PackageManagerEnum = {
|
||||||
|
Bun: 'Bun',
|
||||||
|
PnPm: 'PnPm',
|
||||||
|
Npm: 'Npm',
|
||||||
|
Yarn: 'Yarn',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
// see: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/firefox-webext-browser/index.d.ts
|
||||||
|
export type BrowserSpecificSettings = {
|
||||||
|
browser_specific_settings?: {
|
||||||
|
gecko?: {
|
||||||
|
id: string
|
||||||
|
strict_min_version?: string
|
||||||
|
strict_max_version?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Manifest = ManifestV3Export
|
||||||
|
export type ManifestIcons = chrome.runtime.ManifestIcons
|
||||||
|
export type ManifestBackground = chrome.runtime.ManifestV3['background']
|
||||||
|
export type ManifestContentScripts =
|
||||||
|
chrome.runtime.ManifestV3['content_scripts']
|
||||||
|
export type ManifestWebAccessibleResources =
|
||||||
|
chrome.runtime.ManifestV3['web_accessible_resources']
|
||||||
|
export type ManifestCommands = chrome.runtime.ManifestV3['commands']
|
||||||
|
export type ManifestAction = chrome.runtime.ManifestV3['action']
|
||||||
|
export type ManifestPermissions = chrome.runtime.ManifestV3['permissions']
|
||||||
|
export type ManifestOptionsUI = chrome.runtime.ManifestV3['options_ui']
|
||||||
|
export type ManifestURLOverrides =
|
||||||
|
chrome.runtime.ManifestV3['chrome_url_overrides']
|
||||||
|
|
||||||
|
export type BrowserName<T extends string> = Capitalize<T> | Lowercase<T>
|
||||||
|
export type BrowserEnumType<T extends string> = {
|
||||||
|
[browser in BrowserName<T>]: BrowserName<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BuildMode = AnyCase<Browser>
|
||||||
|
export type BuildTarget = {
|
||||||
|
manifest: Manifest
|
||||||
|
browser: AnyCase<Browser>
|
||||||
|
}
|
||||||
|
export type BuildConfig = {
|
||||||
|
command?: 'build' | 'serve'
|
||||||
|
mode?: AnyCase<Browser> | string | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Repository {
|
||||||
|
type: string
|
||||||
|
url?: string
|
||||||
|
bugs?: Bugs
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Bugs {
|
||||||
|
url?: string
|
||||||
|
email?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Browser = (typeof BrowserEnum)[keyof typeof BrowserEnum]
|
||||||
|
export const Browser: AnyCase<Browser> = createEnum(BrowserEnum)
|
||||||
|
|
||||||
|
export type PackageManager =
|
||||||
|
(typeof PackageManagerEnum)[keyof typeof PackageManagerEnum]
|
||||||
|
export const PackageManager: AnyCase<PackageManager> =
|
||||||
|
createEnum(PackageManagerEnum)
|
||||||
|
|
||||||
|
export type Framework = (typeof FrameworkEnum)[keyof typeof FrameworkEnum]
|
||||||
|
export const Framework: AnyCase<Framework> = createEnum(FrameworkEnum)
|
||||||
|
|
||||||
|
export type Style = (typeof StyleEnum)[keyof typeof StyleEnum]
|
||||||
|
export const Style: AnyCase<Style> = createEnum(StyleEnum)
|
||||||
|
|
||||||
|
export type Language = (typeof LanguageEnum)[keyof typeof LanguageEnum]
|
||||||
|
export const Language: AnyCase<Language> = createEnum(LanguageEnum)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
export type ObjectValues<T> = T[keyof T]
|
||||||
|
|
||||||
|
export function createEnum<T extends Record<string, string>>(enumObj: T) {
|
||||||
|
return Object.values(enumObj) as unknown as ObjectValues<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AnyCase<T extends string> =
|
||||||
|
| Uppercase<T>
|
||||||
|
| Lowercase<T>
|
||||||
|
| Capitalize<T>
|
||||||
|
| Uncapitalize<T>
|
||||||
|
|
||||||
|
export type AnyCaseLanguage<T extends string, K extends string> =
|
||||||
|
| Uppercase<T | K>
|
||||||
|
| Lowercase<T | K>
|
||||||
|
| Capitalize<T | K>
|
||||||
|
| Uncapitalize<T | K>
|
||||||
|
|
||||||
|
export type OptionalKeys<T> = {
|
||||||
|
[K in keyof T as undefined extends T[K] ? K : never]: T[K]
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"manifest_version": 3,
|
|
||||||
"name": "BetterSEQTA+",
|
|
||||||
"version": "3.2.6",
|
|
||||||
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development, and incorporate a plethora of new features!",
|
|
||||||
"icons": {
|
|
||||||
"32": "src/resources/icons/icon-32.png",
|
|
||||||
"48": "src/resources/icons/icon-48.png",
|
|
||||||
"64": "src/resources/icons/icon-64.png"
|
|
||||||
},
|
|
||||||
"action": {
|
|
||||||
"browser_style": true,
|
|
||||||
"default_popup": "src/interface/index.html#settings",
|
|
||||||
"default_icon": {
|
|
||||||
"32": "src/resources/icons/icon-32.png",
|
|
||||||
"48": "src/resources/icons/icon-48.png",
|
|
||||||
"64": "src/resources/icons/icon-64.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"permissions": ["tabs", "notifications", "storage", "activeTab"],
|
|
||||||
"host_permissions": ["<all_urls>"],
|
|
||||||
"background": {
|
|
||||||
"scripts": ["src/background.ts"]
|
|
||||||
},
|
|
||||||
"content_scripts": [
|
|
||||||
{
|
|
||||||
"matches": ["*://*/*"],
|
|
||||||
"js": ["src/SEQTA.ts"],
|
|
||||||
"run_at": "document_start"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
+22
-8
@@ -1,15 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "betterseqtaplus",
|
"name": "betterseqtaplus",
|
||||||
"version": "3.3.0",
|
"version": "3.3.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development, and incorporate a plethora of new features!",
|
"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",
|
"browserslist": "> 0.5%, last 2 versions, not dead",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "MODE=chrome vite dev",
|
||||||
"dev:firefox": "VITE_TARGET=firefox vite build --watch",
|
"dev:firefox": "MODE=firefox vite build --watch",
|
||||||
"build": "vite build",
|
"build": "MODE=chrome vite build && MODE=firefox vite build",
|
||||||
"build:firefox": "VITE_TARGET=firefox vite build",
|
"build:chrome": "MODE=chrome vite build",
|
||||||
"package": "rimraf ./dist/*.map && 7z a -tzip extension.zip ./dist/*"
|
"build:firefox": "MODE=firefox vite build",
|
||||||
|
"build:safari": "MODE=safari vite build",
|
||||||
|
"convert:safari": "xcrun safari-web-extension-converter dist/safari --project-location . --app-name $npm_package_name-safari",
|
||||||
|
"release": "gh release create $npm_package_name@$npm_package_version ./dist/*.zip --generate-notes",
|
||||||
|
"publish": "bun lib/publish.js --b",
|
||||||
|
"zip": "bedframe zip"
|
||||||
},
|
},
|
||||||
"targets": {
|
"targets": {
|
||||||
"prod": {
|
"prod": {
|
||||||
@@ -19,22 +24,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": {
|
||||||
|
"name": "SethBurkart123",
|
||||||
|
"email": "betterseqta@betterseqta.com",
|
||||||
|
"url": "https://github.com/BetterSEQTA/BetterSEQTA-plus"
|
||||||
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@crxjs/vite-plugin": "^2.0.0-beta.23",
|
"@crxjs/vite-plugin": "^2.0.0-beta.23",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
"@vitejs/plugin-react-swc": "^3.6.0",
|
"@vitejs/plugin-react-swc": "^3.6.0",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
|
"glob": "^11.0.0",
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
"parcel": "^2.11.0",
|
"parcel": "^2.11.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"sass": "^1.70.0",
|
"sass": "^1.70.0",
|
||||||
"sass-loader": "^13.3.3",
|
"sass-loader": "^13.3.3",
|
||||||
|
"semver": "^7.6.3",
|
||||||
"url": "^0.11.3"
|
"url": "^0.11.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@bedframe/cli": "^0.0.85",
|
||||||
"@blocknote/core": "^0.14.1",
|
"@blocknote/core": "^0.14.1",
|
||||||
"@blocknote/mantine": "^0.14.1",
|
"@blocknote/mantine": "^0.14.1",
|
||||||
"@blocknote/react": "^0.14.1",
|
"@blocknote/react": "^0.14.1",
|
||||||
@@ -59,10 +71,12 @@
|
|||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
"dompurify": "^3.0.8",
|
"dompurify": "^3.0.8",
|
||||||
"framer-motion": "^11.0.25",
|
"framer-motion": "^11.0.25",
|
||||||
|
"kolorist": "^1.8.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"million": "latest",
|
"million": "latest",
|
||||||
"motion": "^10.17.0",
|
"motion": "^10.17.0",
|
||||||
|
"publish-browser-extension": "^2.2.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-best-gradient-color-picker": "3.0.5",
|
"react-best-gradient-color-picker": "3.0.5",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -76,7 +90,7 @@
|
|||||||
"ts-loader": "^9.5.1",
|
"ts-loader": "^9.5.1",
|
||||||
"typescript": "^5.3.3",
|
"typescript": "^5.3.3",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"vite": "^5.2.2",
|
"vite": "^5.4.2",
|
||||||
"webextension-polyfill": "^0.10.0"
|
"webextension-polyfill": "^0.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-29
@@ -5,42 +5,36 @@ import browser from 'webextension-polyfill'
|
|||||||
import { animate, spring, stagger } from 'motion'
|
import { animate, spring, stagger } from 'motion'
|
||||||
|
|
||||||
// Internal utilities and functions
|
// Internal utilities and functions
|
||||||
import { delay } from './seqta/utils/delay'
|
import { delay } from '@/seqta/utils/delay'
|
||||||
import stringToHTML from './seqta/utils/stringToHTML'
|
import stringToHTML from '@/seqta/utils/stringToHTML'
|
||||||
import { MessageHandler } from './seqta/utils/listeners/MessageListener'
|
import { MessageHandler } from '@/seqta/utils/listeners/MessageListener'
|
||||||
import { initializeSettingsState, settingsState } from './seqta/utils/listeners/SettingsState'
|
import { initializeSettingsState, settingsState } from '@/seqta/utils/listeners/SettingsState'
|
||||||
import { StorageChangeHandler } from './seqta/utils/listeners/StorageChanges'
|
import { StorageChangeHandler } from '@/seqta/utils/listeners/StorageChanges'
|
||||||
import { eventManager } from './seqta/utils/listeners/EventManager'
|
import { eventManager } from '@/seqta/utils/listeners/EventManager'
|
||||||
|
|
||||||
// UI and theme management
|
// UI and theme management
|
||||||
import loading, { AppendLoadingSymbol } from './seqta/ui/Loading'
|
import loading, { AppendLoadingSymbol } from '@/seqta/ui/Loading'
|
||||||
import { enableCurrentTheme } from './seqta/ui/themes/enableCurrent'
|
import { enableCurrentTheme } from '@/seqta/ui/themes/enableCurrent'
|
||||||
import { updateAllColors } from './seqta/ui/colors/Manager'
|
import { updateAllColors } from '@/seqta/ui/colors/Manager'
|
||||||
import { SettingsResizer } from './seqta/ui/SettingsResizer'
|
import { SettingsResizer } from '@/seqta/ui/SettingsResizer'
|
||||||
import { AddBetterSEQTAElements } from './seqta/ui/AddBetterSEQTAElements'
|
import { AddBetterSEQTAElements } from '@/seqta/ui/AddBetterSEQTAElements'
|
||||||
|
|
||||||
// JSON content
|
// JSON content
|
||||||
import MenuitemSVGKey from './seqta/content/MenuItemSVGKey.json'
|
import MenuitemSVGKey from '@/seqta/content/MenuItemSVGKey.json'
|
||||||
import ShortcutLinks from './seqta/content/links.json'
|
import ShortcutLinks from '@/seqta/content/links.json'
|
||||||
|
|
||||||
// Icons and fonts
|
// Icons and fonts
|
||||||
import IconFamily from './resources/fonts/IconFamily.woff'
|
import IconFamily from '@/resources/fonts/IconFamily.woff'
|
||||||
import LogoLight from './resources/icons/betterseqta-light-icon.png'
|
import LogoLight from '@/resources/icons/betterseqta-light-icon.png'
|
||||||
import LogoLightOutline from './resources/icons/betterseqta-light-outline.png'
|
import LogoLightOutline from '@/resources/icons/betterseqta-light-outline.png'
|
||||||
import icon48 from './resources/icons/icon-48.png?base64'
|
import icon48 from '@/resources/icons/icon-48.png?base64'
|
||||||
import assessmentsicon from './seqta/icons/assessmentsIcon'
|
import assessmentsicon from '@/seqta/icons/assessmentsIcon'
|
||||||
import coursesicon from './seqta/icons/coursesIcon'
|
import coursesicon from '@/seqta/icons/coursesIcon'
|
||||||
|
|
||||||
// Stylesheets
|
// Stylesheets
|
||||||
import iframeCSS from './css/iframe.scss?raw'
|
import iframeCSS from '@/css/iframe.scss?raw'
|
||||||
import injectedCSS from './css/injected.scss?inline'
|
import injectedCSS from '@/css/injected.scss?inline'
|
||||||
import documentLoadCSS from './css/documentload.scss?inline'
|
import documentLoadCSS from '@/css/documentload.scss?inline'
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
chrome?: any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let SettingsClicked = false
|
let SettingsClicked = false
|
||||||
export let MenuOptionsOpen = false
|
export let MenuOptionsOpen = false
|
||||||
@@ -975,7 +969,7 @@ export function addExtensionSettings() {
|
|||||||
if (extensionContainer) extensionContainer.appendChild(extensionPopup)
|
if (extensionContainer) extensionContainer.appendChild(extensionPopup)
|
||||||
|
|
||||||
const extensionIframe: HTMLIFrameElement = document.createElement('iframe')
|
const extensionIframe: HTMLIFrameElement = document.createElement('iframe')
|
||||||
extensionIframe.src = `${browser.runtime.getURL('src/interface/index.html')}#settings/embedded`
|
extensionIframe.src = `${browser.runtime.getURL('interface/index.html')}#settings/embedded`
|
||||||
extensionIframe.id = 'ExtensionIframe'
|
extensionIframe.id = 'ExtensionIframe'
|
||||||
extensionIframe.setAttribute('allowTransparency', 'true')
|
extensionIframe.setAttribute('allowTransparency', 'true')
|
||||||
extensionIframe.setAttribute('excludeDarkCheck', 'true')
|
extensionIframe.setAttribute('excludeDarkCheck', 'true')
|
||||||
|
|||||||
@@ -245,13 +245,14 @@ const ThemeSelector: ForwardRefExoticComponent<Omit<ThemeSelectorProps, "ref"> &
|
|||||||
className="w-full h-[1px] my-2 bg-zinc-100 dark:bg-zinc-600"
|
className="w-full h-[1px] my-2 bg-zinc-100 dark:bg-zinc-600"
|
||||||
></div>}
|
></div>}
|
||||||
|
|
||||||
<button
|
<a
|
||||||
onClick={() => browser.tabs.create({ url: browser.runtime.getURL('src/interface/index.html#store')})}
|
href={browser.runtime.getURL('interface/index.html#store')}
|
||||||
|
target="_blank"
|
||||||
className="flex items-center justify-center w-full transition aspect-theme rounded-xl bg-zinc-100 dark:bg-zinc-900 dark:text-white"
|
className="flex items-center justify-center w-full transition aspect-theme rounded-xl bg-zinc-100 dark:bg-zinc-900 dark:text-white"
|
||||||
>
|
>
|
||||||
<span className="text-xl font-IconFamily">{'\uecc5'}</span>
|
<span className="text-xl font-IconFamily">{'\uecc5'}</span>
|
||||||
<span className="ml-2">Theme Store</span>
|
<span className="ml-2">Theme Store</span>
|
||||||
</button>
|
</a>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => browser.runtime.sendMessage({ type: 'currentTab', info: 'OpenThemeCreator' })}
|
onClick={() => browser.runtime.sendMessage({ type: 'currentTab', info: 'OpenThemeCreator' })}
|
||||||
|
|||||||
@@ -15,3 +15,7 @@
|
|||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button, a {
|
||||||
|
@apply text-[0.875rem];
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { createManifest } from '../../lib/createManifest'
|
||||||
|
import baseManifest from './manifest.json'
|
||||||
|
|
||||||
|
export const brave = createManifest(baseManifest, 'brave')
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { createManifest } from '../../lib/createManifest'
|
||||||
|
import baseManifest from './manifest.json'
|
||||||
|
|
||||||
|
export const chrome = createManifest(baseManifest, 'chrome')
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { createManifest } from '../../lib/createManifest'
|
||||||
|
import baseManifest from './manifest.json'
|
||||||
|
|
||||||
|
export const edge = createManifest(baseManifest, 'edge')
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { createManifest } from '../../lib/createManifest'
|
||||||
|
import baseManifest from './manifest.json'
|
||||||
|
import pkg from '../../package.json'
|
||||||
|
|
||||||
|
const updatedFirefoxManifest = {
|
||||||
|
...baseManifest,
|
||||||
|
background: {
|
||||||
|
scripts: [baseManifest.background.service_worker],
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
"default_popup": "interface/index.html#settings",
|
||||||
|
},
|
||||||
|
browser_specific_settings: {
|
||||||
|
gecko: {
|
||||||
|
id: pkg.author.email,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const firefox = createManifest(updatedFirefoxManifest, 'firefox')
|
||||||
@@ -4,38 +4,38 @@
|
|||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development add add heaps more features!",
|
"description": "Enhance SEQTA Learn's usability and aesthetics! A fork of BetterSEQTA to continue development add add heaps more features!",
|
||||||
"icons": {
|
"icons": {
|
||||||
"32": "src/resources/icons/icon-32.png",
|
"32": "resources/icons/icon-32.png",
|
||||||
"48": "src/resources/icons/icon-48.png",
|
"48": "resources/icons/icon-48.png",
|
||||||
"64": "src/resources/icons/icon-64.png"
|
"64": "resources/icons/icon-64.png"
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
"browser_style": true,
|
"browser_style": true,
|
||||||
"default_popup": "src/interface/index.html#settings",
|
"default_popup": "interface/index.html#settings",
|
||||||
"default_icon": {
|
"default_icon": {
|
||||||
"32": "src/resources/icons/icon-32.png",
|
"32": "resources/icons/icon-32.png",
|
||||||
"48": "src/resources/icons/icon-48.png",
|
"48": "resources/icons/icon-48.png",
|
||||||
"64": "src/resources/icons/icon-64.png"
|
"64": "resources/icons/icon-64.png"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permissions": ["tabs", "notifications", "storage"],
|
"permissions": ["tabs", "notifications", "storage"],
|
||||||
"host_permissions": ["https://newsapi.org/", "*://*/*"],
|
"host_permissions": ["https://newsapi.org/", "*://*/*"],
|
||||||
"background": {
|
"background": {
|
||||||
"service_worker": "src/background.ts"
|
"service_worker": "background.ts"
|
||||||
},
|
},
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["*://*/*"],
|
"matches": ["*://*/*"],
|
||||||
"js": ["src/SEQTA.ts"],
|
"js": ["SEQTA.ts"],
|
||||||
"run_at": "document_start"
|
"run_at": "document_start"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"web_accessible_resources": [
|
"web_accessible_resources": [
|
||||||
{
|
{
|
||||||
"resources": ["src/interface/index.html"],
|
"resources": ["interface/index.html"],
|
||||||
"matches": ["*://*/*"]
|
"matches": ["*://*/*"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resources": ["src/seqta/ui/background/background.html"],
|
"resources": ["seqta/ui/background/background.html"],
|
||||||
"matches": ["*://*/*"]
|
"matches": ["*://*/*"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { createManifest } from '../../lib/createManifest'
|
||||||
|
import baseManifest from './manifest.json'
|
||||||
|
|
||||||
|
export const opera = createManifest(baseManifest, 'opera')
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { createManifest } from '../../lib/createManifest'
|
||||||
|
import baseManifest from './manifest.json'
|
||||||
|
|
||||||
|
const updatedSafariManifest = {
|
||||||
|
...baseManifest,
|
||||||
|
browser_specific_settings: {
|
||||||
|
safari: {
|
||||||
|
strict_min_version: '15.4',
|
||||||
|
strict_max_version: '*',
|
||||||
|
},
|
||||||
|
// ^^^ https://developer.apple.com/documentation/safariservices/safari_web_extensions/optimizing_your_web_extension_for_safari#3743239
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings#safari_properties
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const safari = createManifest(updatedSafariManifest, 'safari')
|
||||||
@@ -8,6 +8,6 @@ export async function appendBackgroundToUI() {
|
|||||||
background.id = 'background';
|
background.id = 'background';
|
||||||
background.classList.add('imageBackground');
|
background.classList.add('imageBackground');
|
||||||
background.setAttribute('excludeDarkCheck', 'true');
|
background.setAttribute('excludeDarkCheck', 'true');
|
||||||
background.src = browser.runtime.getURL('src/seqta/ui/background/background.html');
|
background.src = browser.runtime.getURL('seqta/ui/background/background.html');
|
||||||
parent!.appendChild(background);
|
parent!.appendChild(background);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export function OpenThemeCreator( themeID: string = '' ) {
|
|||||||
const width = '310px';
|
const width = '310px';
|
||||||
|
|
||||||
const themeCreatorIframe: HTMLIFrameElement = document.createElement('iframe');
|
const themeCreatorIframe: HTMLIFrameElement = document.createElement('iframe');
|
||||||
themeCreatorIframe.src = `${browser.runtime.getURL('src/interface/index.html')}${ themeID != '' ? `?themeID=${themeID}` : '' }#themeCreator`;
|
themeCreatorIframe.src = `${browser.runtime.getURL('interface/index.html')}${ themeID != '' ? `?themeID=${themeID}` : '' }#themeCreator`;
|
||||||
themeCreatorIframe.id = 'themeCreatorIframe';
|
themeCreatorIframe.id = 'themeCreatorIframe';
|
||||||
themeCreatorIframe.setAttribute('allowTransparency', 'true');
|
themeCreatorIframe.setAttribute('allowTransparency', 'true');
|
||||||
themeCreatorIframe.setAttribute('excludeDarkCheck', 'true');
|
themeCreatorIframe.setAttribute('excludeDarkCheck', 'true');
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class StorageManager {
|
|||||||
/**
|
/**
|
||||||
* Register a listener for a setting.
|
* Register a listener for a setting.
|
||||||
* @param prop The setting to listen to.
|
* @param prop The setting to listen to.
|
||||||
* @param listener The listener to call when the setting changes.
|
* @param listener The listener to call when the setting changes -> takes two arguments, (newValue, oldValue)
|
||||||
*/
|
*/
|
||||||
public register(prop: keyof SettingsState, listener: ChangeListener): void {
|
public register(prop: keyof SettingsState, listener: ChangeListener): void {
|
||||||
if (!this.listeners[prop]) {
|
if (!this.listeners[prop]) {
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ export class StorageChangeHandler {
|
|||||||
updateAllColors();
|
updateAllColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleOnOffChange() {
|
private handleOnOffChange(newValue: boolean) {
|
||||||
|
if (newValue) return;
|
||||||
browser.runtime.sendMessage({ type: 'reloadTabs' });
|
browser.runtime.sendMessage({ type: 'reloadTabs' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,5 +19,10 @@
|
|||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"],
|
||||||
|
"$lib": ["./lib/*"],
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-33
@@ -1,45 +1,46 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import { join } from 'path';
|
import { join, resolve } from 'path';
|
||||||
import fs from 'fs';
|
|
||||||
import mime from 'mime-types';
|
|
||||||
|
|
||||||
import manifest from './manifest.json';
|
import type { BuildTarget } from './lib/types';
|
||||||
import firefoxManifest from './manifest.firefox.json';
|
|
||||||
|
//import MillionLint from '@million/lint';
|
||||||
|
|
||||||
import react from '@vitejs/plugin-react-swc';
|
import react from '@vitejs/plugin-react-swc';
|
||||||
//import MillionLint from '@million/lint';
|
|
||||||
import { crx } from '@crxjs/vite-plugin';
|
|
||||||
import million from "million/compiler";
|
import million from "million/compiler";
|
||||||
|
import { base64Loader } from './lib/base64loader';
|
||||||
|
|
||||||
const isFirefox = process.env.VITE_TARGET === 'firefox';
|
import { chrome } from './src/manifests/chrome';
|
||||||
|
import { brave } from './src/manifests/brave';
|
||||||
|
import { edge } from './src/manifests/edge';
|
||||||
|
import { firefox } from './src/manifests/firefox';
|
||||||
|
import { opera } from './src/manifests/opera';
|
||||||
|
import { safari } from './src/manifests/safari';
|
||||||
|
import { crx } from '@crxjs/vite-plugin';
|
||||||
|
|
||||||
const base64Loader = {
|
const targets: BuildTarget[] = [
|
||||||
name: "base64-loader",
|
chrome, brave, edge, firefox, opera, safari
|
||||||
transform(_: any, id: string) {
|
]
|
||||||
const [filePath, query] = id.split("?");
|
|
||||||
if (query !== "base64") return null;
|
|
||||||
|
|
||||||
const data = fs.readFileSync(filePath, { encoding: 'base64' });
|
const mode = process.env.MODE || 'chrome';
|
||||||
const mimeType = mime.lookup(filePath);
|
|
||||||
const dataURL = `data:${mimeType};base64,${data}`;
|
|
||||||
|
|
||||||
return `export default '${dataURL}';`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const plugins = [
|
|
||||||
react(),
|
|
||||||
base64Loader,
|
|
||||||
million.vite({ auto: true }),
|
|
||||||
//MillionLint.vite(), /* enable for testing and debugging performance */
|
|
||||||
crx({
|
|
||||||
manifest: isFirefox ? firefoxManifest : manifest,
|
|
||||||
browser: isFirefox ? 'firefox' : 'chrome'
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: plugins,
|
plugins: [
|
||||||
|
base64Loader,
|
||||||
|
react(),
|
||||||
|
million.vite({ auto: true }),
|
||||||
|
//MillionLint.vite(), /* enable for testing and debugging performance */
|
||||||
|
crx({
|
||||||
|
manifest: targets.find(t => t.browser === mode.toLowerCase())?.manifest ?? chrome.manifest,
|
||||||
|
browser: mode.toLowerCase() === "firefox" ? "firefox" : "chrome"
|
||||||
|
})
|
||||||
|
],
|
||||||
|
root: resolve(__dirname, './src'),
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': resolve(__dirname, './src'),
|
||||||
|
'$lib': resolve(__dirname, './lib'),
|
||||||
|
},
|
||||||
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 5173,
|
||||||
hmr: {
|
hmr: {
|
||||||
@@ -49,7 +50,9 @@ export default defineConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
minify: true,
|
outDir: resolve(__dirname, 'dist', mode),
|
||||||
|
emptyOutDir: true,
|
||||||
|
minify: false,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: {
|
input: {
|
||||||
settings: join(__dirname, 'src', 'interface', 'index.html'),
|
settings: join(__dirname, 'src', 'interface', 'index.html'),
|
||||||
|
|||||||
Reference in New Issue
Block a user