diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 00000000..843f6438 Binary files /dev/null and b/bun.lockb differ diff --git a/src/popup/.eslintrc.cjs b/interface/.eslintrc.cjs similarity index 100% rename from src/popup/.eslintrc.cjs rename to interface/.eslintrc.cjs diff --git a/src/popup/.gitignore b/interface/.gitignore similarity index 100% rename from src/popup/.gitignore rename to interface/.gitignore diff --git a/src/popup/README.md b/interface/README.md similarity index 100% rename from src/popup/README.md rename to interface/README.md diff --git a/src/popup/bun.lockb b/interface/bun.lockb similarity index 100% rename from src/popup/bun.lockb rename to interface/bun.lockb diff --git a/src/popup/index.html b/interface/index.html similarity index 100% rename from src/popup/index.html rename to interface/index.html diff --git a/src/popup/package.json b/interface/package.json similarity index 100% rename from src/popup/package.json rename to interface/package.json diff --git a/src/popup/postcss.config.js b/interface/postcss.config.js similarity index 100% rename from src/popup/postcss.config.js rename to interface/postcss.config.js diff --git a/src/popup/public/vite.svg b/interface/public/vite.svg similarity index 100% rename from src/popup/public/vite.svg rename to interface/public/vite.svg diff --git a/src/popup/src/App.css b/interface/src/App.css similarity index 100% rename from src/popup/src/App.css rename to interface/src/App.css diff --git a/interface/src/App.tsx b/interface/src/App.tsx new file mode 100644 index 00000000..b0b4872e --- /dev/null +++ b/interface/src/App.tsx @@ -0,0 +1,75 @@ +// App.tsx +import { useState } from 'react'; +import TabbedContainer from './components/TabbedContainer'; +import Settings from './pages/Settings'; +import logo from './assets/betterseqta-dark-full.png'; +import logoDark from './assets/betterseqta-light-full.png'; +import Shortcuts from './pages/Shortcuts'; +import About from './pages/About'; + +export interface SettingsState { + notificationCollector: boolean; + lessonAlerts: boolean; + animatedBackground: boolean; + animatedBackgroundSpeed: boolean; + customThemeColor: string; + betterSEQTAPlus: boolean; +} + +const App: React.FC = () => { + const [settingsState, setSettingsState] = useState({ + notificationCollector: false, + lessonAlerts: false, + animatedBackground: false, + animatedBackgroundSpeed: false, + customThemeColor: "#db6969", + betterSEQTAPlus: true + }); + + // Handler for Switches + const switchChange = (key: string, isOn: boolean) => { + setSettingsState({ + ...settingsState, + [key]: isOn, + }); + }; + + // Handler for ColorPicker + const colorChange = (color: string) => { + setSettingsState({ + ...settingsState, + customThemeColor: color, + }); + }; + + const tabs = [ + { + title: 'Settings', + content: + }, + { + title: 'Shortcuts', + content: + }, + { + title: 'About', + content: + } + ]; + + return ( +
+ +
+
+ + +
+ +
+ +
+ ); +} + +export default App; \ No newline at end of file diff --git a/src/popup/src/assets/betterseqta-dark-full.png b/interface/src/assets/betterseqta-dark-full.png similarity index 100% rename from src/popup/src/assets/betterseqta-dark-full.png rename to interface/src/assets/betterseqta-dark-full.png diff --git a/src/popup/src/assets/betterseqta-light-full.png b/interface/src/assets/betterseqta-light-full.png similarity index 100% rename from src/popup/src/assets/betterseqta-light-full.png rename to interface/src/assets/betterseqta-light-full.png diff --git a/src/popup/src/assets/react.svg b/interface/src/assets/react.svg similarity index 100% rename from src/popup/src/assets/react.svg rename to interface/src/assets/react.svg diff --git a/interface/src/components/ColorPicker.tsx b/interface/src/components/ColorPicker.tsx new file mode 100644 index 00000000..84bd298d --- /dev/null +++ b/interface/src/components/ColorPicker.tsx @@ -0,0 +1,45 @@ +// TODO: Create types for ColorPicker +// @ts-expect-error No typescript declarations available +import ColorPicker from 'react-best-gradient-color-picker'; +import { useState, useRef, useEffect } from 'react'; + +interface ColorPickerProps { + color: string; + onChange: (color: string) => void; +} + +const Picker = ({ color, onChange }: ColorPickerProps) => { + const [showPicker, setShowPicker] = useState(false); + const ref = useRef(null); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent): void => { + if (ref.current && !ref.current.contains(event.target as Node)) { + setShowPicker(false); + } + }; + if (showPicker) { + document.addEventListener('mousedown', handleClickOutside); + } + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [showPicker]); + + return ( +
+ + {showPicker && ( +
+ +
+ )} +
+ ); +}; + +export default Picker; diff --git a/src/popup/src/components/Slider.css b/interface/src/components/Slider.css similarity index 100% rename from src/popup/src/components/Slider.css rename to interface/src/components/Slider.css diff --git a/src/popup/src/components/Slider.tsx b/interface/src/components/Slider.tsx similarity index 100% rename from src/popup/src/components/Slider.tsx rename to interface/src/components/Slider.tsx diff --git a/src/popup/src/components/Switch.css b/interface/src/components/Switch.css similarity index 70% rename from src/popup/src/components/Switch.css rename to interface/src/components/Switch.css index 019c0c56..d7e84449 100644 --- a/src/popup/src/components/Switch.css +++ b/interface/src/components/Switch.css @@ -1,4 +1,3 @@ .switch[data-ison="true"] { - justify-content: end; background-color: #30D259; } \ No newline at end of file diff --git a/src/popup/src/components/Switch.tsx b/interface/src/components/Switch.tsx similarity index 76% rename from src/popup/src/components/Switch.tsx rename to interface/src/components/Switch.tsx index 19996a3c..62dacfec 100644 --- a/src/popup/src/components/Switch.tsx +++ b/interface/src/components/Switch.tsx @@ -1,31 +1,30 @@ -import { useState } from "react"; import { motion } from "framer-motion"; import "./Switch.css"; interface SwitchProps { onChange: (isOn: boolean) => void; + state: boolean; } export default function Switch(props: SwitchProps) { - const [isOn, setIsOn] = useState(false); - const toggleSwitch = () => { - const newIsOn = !isOn; - setIsOn(newIsOn); + const newIsOn = !props.state; props.onChange(newIsOn); }; return (
+ />
); } diff --git a/interface/src/components/TabbedContainer.tsx b/interface/src/components/TabbedContainer.tsx new file mode 100644 index 00000000..91df24dd --- /dev/null +++ b/interface/src/components/TabbedContainer.tsx @@ -0,0 +1,92 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { motion } from 'framer-motion'; + +interface Tab { + title: string; + content: JSX.Element; +} + +interface TabbedContainerProps { + tabs: Tab[]; + themeColor: string; +} + +const TabbedContainer: React.FC = ({ tabs, themeColor }) => { + const [activeTab, setActiveTab] = useState(0); + const [hoveredTab, setHoveredTab] = useState(null); + const [tabWidth, setTabWidth] = useState(0); + const [position, setPosition] = useState(0); + const positionRef = useRef(position); + + useEffect(() => { + const newPosition = -activeTab * 100; + setPosition(newPosition); + positionRef.current = newPosition; + }, [activeTab]); + + const containerRef = useRef(null); + + const springTransition = { type: 'spring', stiffness: 250, damping: 25 }; + + useEffect(() => { + if (containerRef.current) { + // @ts-expect-error for some reason its giving an error in TS but it works... + const width = containerRef.current.getBoundingClientRect().width; + setTabWidth(width / tabs.length); + } + }, [tabs.length]); + + const calcXPos = (index: number | null) => { + if (index !== null) { + return tabWidth * index; + } + return tabWidth * activeTab; + }; + + return ( +
+
+
+ + {tabs.map((tab, index) => ( + + ))} +
+
+
+ +
+ {tabs.map((tab, index) => ( +
+ {tab.content} +
+ ))} +
+
+
+
+ ); +}; + +export default TabbedContainer; diff --git a/src/popup/src/index.css b/interface/src/index.css similarity index 100% rename from src/popup/src/index.css rename to interface/src/index.css diff --git a/src/popup/src/main.tsx b/interface/src/main.tsx similarity index 100% rename from src/popup/src/main.tsx rename to interface/src/main.tsx diff --git a/interface/src/pages/About.tsx b/interface/src/pages/About.tsx new file mode 100644 index 00000000..53197a2a --- /dev/null +++ b/interface/src/pages/About.tsx @@ -0,0 +1,10 @@ +const About: React.FC = () => { + + return ( +
+

About

+
+ ); +}; + +export default About; diff --git a/interface/src/pages/Settings.tsx b/interface/src/pages/Settings.tsx new file mode 100644 index 00000000..71a13851 --- /dev/null +++ b/interface/src/pages/Settings.tsx @@ -0,0 +1,68 @@ +import Switch from '../components/Switch'; +import ColorPicker from '../components/ColorPicker'; +import { SettingsState } from '../App'; + +interface ISetting { + title: string; + description: string; + modifyElement: JSX.Element; +} + +interface SettingsProps { + settingsState: SettingsState; + switchChange: (key: string, isOn: boolean) => void; + colorChange: (color: string) => void; +} + +const Settings: React.FC = ({ settingsState, switchChange, colorChange }) => { + const settings: ISetting[] = [ + { + title: "Notification Collector", + description: "Uncaps the 9+ limit for notifications, showing the real number.", + modifyElement: switchChange('notificationCollector', isOn)} /> + }, + { + title: "Lesson Alerts", + description: "Sends a native browser notification ~5 minutes prior to lessons.", + modifyElement: switchChange('lessonAlerts', isOn)} /> + }, + { + title: "Animated Background", + description: "Adds an animated background to BetterSEQTA. (May impact battery life)", + modifyElement: switchChange('animatedBackground', isOn)} /> + }, + { + title: "Animated Background Speed", + description: "Controls the speed of the animated background.", + modifyElement: switchChange('animatedBackgroundSpeed', isOn)} /> + }, + { + title: "Custom Theme Colour", + description: "Customise the overall theme colour of SEQTA Learn.", + modifyElement: colorChange(color)} /> + }, + { + title: "BetterSEQTA+", + description: "Unlocks premium features.", + modifyElement: switchChange('betterSEQTAPlus', isOn)} /> + } + ]; + + return ( +
+ {settings.map((setting, index) => ( +
+
+

{setting.title}

+

{setting.description}

+
+
+ {setting.modifyElement} +
+
+ ))} +
+ ); +}; + +export default Settings; diff --git a/interface/src/pages/Shortcuts.tsx b/interface/src/pages/Shortcuts.tsx new file mode 100644 index 00000000..7400df6a --- /dev/null +++ b/interface/src/pages/Shortcuts.tsx @@ -0,0 +1,95 @@ +import { useState } from "react"; +import Switch from "../components/Switch"; + +export default function Shortcuts() { + const [shortcutState, setShortcutState] = useState({ + youtube: false, + outlook: false, + office: false, + spotify: false, + google: false, + duckduckgo: false, + coolmathgames: false, + sace: false, + googlescholar: false, + gmail: false, + netflix: false + }); + + // Handler for Switches + const switchChange = (key: string, isOn: boolean) => { + setShortcutState({ + ...shortcutState, + [key]: isOn, + }); + }; + + const DefaultShortcuts = [ + { + title: "YouTube", + link: "https://youtube.com", + modifyElement: switchChange('youtube', isOn)} /> + }, + { + title: "Outlook", + link: "https://outlook.office.com/mail/inbox", + modifyElement: switchChange('outlook', isOn)} /> + }, + { + title: "Office", + link: "https://www.office.com/", + modifyElement: switchChange('office', isOn)} /> + }, + { + title: "Spotify", + link: "https://www.spotify.com/", + modifyElement: switchChange('spotify', isOn)} /> + }, + { + title: "Google", + link: "https://www.google.com/", + modifyElement: switchChange('google', isOn)} /> + }, + { + title: "DuckDuckGo", + link: "https://duckduckgo.com/", + modifyElement: switchChange('duckduckgo', isOn)} /> + }, + { + title: "Cool Math Games", + link: "https://www.coolmathgames.com/", + modifyElement: switchChange('coolmathgames', isOn)} /> + }, + { + title: "SACE", + link: "https://www.sace.sa.edu.au/", + modifyElement: switchChange('sace', isOn)} /> + }, + { + title: "Google Scholar", + link: "https://scholar.google.com/", + modifyElement: switchChange('googlescholar', isOn)} /> + }, + { + title: "Gmail", + link: "https://mail.google.com/", + modifyElement: switchChange('gmail', isOn)} /> + }, + { + title: "Netflix", + link: "https://www.netflix.com/", + modifyElement: switchChange('netflix', isOn)} /> + } + ]; + + return ( +
+ {DefaultShortcuts.map((shortcut, index) => ( +
+ {shortcut.title} + {shortcut.modifyElement} +
+ ))} +
+ ); +} diff --git a/src/popup/src/vite-env.d.ts b/interface/src/vite-env.d.ts similarity index 100% rename from src/popup/src/vite-env.d.ts rename to interface/src/vite-env.d.ts diff --git a/interface/tailwind.config.js b/interface/tailwind.config.js new file mode 100644 index 00000000..1cc7babf --- /dev/null +++ b/interface/tailwind.config.js @@ -0,0 +1,22 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + darkMode: "class", + theme: { + fontSize: { + 'xs': '.65rem', + 'sm': '.775rem', + 'base': '0.65rem', // 16px + 'md': '0.65rem', // 16px + 'lg': '1rem', // 18px + 'xl': '1.25rem', // 20px + '2xl': '1.5rem', // 24px + '3xl': '1.875rem', // 30px + } + }, + plugins: [], +} + diff --git a/src/popup/tsconfig.json b/interface/tsconfig.json similarity index 100% rename from src/popup/tsconfig.json rename to interface/tsconfig.json diff --git a/src/popup/tsconfig.node.json b/interface/tsconfig.node.json similarity index 100% rename from src/popup/tsconfig.node.json rename to interface/tsconfig.node.json diff --git a/src/popup/vite.config.ts b/interface/vite.config.ts similarity index 90% rename from src/popup/vite.config.ts rename to interface/vite.config.ts index 4d2fbbab..6c98fca4 100644 --- a/src/popup/vite.config.ts +++ b/interface/vite.config.ts @@ -5,7 +5,7 @@ import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], build: { - outDir: '../../public/popup-dist', + //outDir: '../../public/popup-dist', rollupOptions: { output: { assetFileNames: 'client/rsc/[ext]/[name][extname]', diff --git a/public/manifest.json b/public/manifest.json index 254a7cde..c05fac74 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -20,8 +20,7 @@ "permissions": ["tabs", "notifications", "storage"], "host_permissions": ["https://newsapi.org/", "*://*/*"], "background": { - "content_scripts": "background.js", - "persistent": false + "service_worker": "background.js" }, "optional_permissions": ["declarativeContent"], "content_scripts": [ diff --git a/src/popup/src/App.tsx b/src/popup/src/App.tsx deleted file mode 100644 index 6f749e9f..00000000 --- a/src/popup/src/App.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import './App.css' -import Switch from './components/Switch' -import logo from './assets/betterseqta-dark-full.png' -import logoDark from './assets/betterseqta-light-full.png' -import ColorPicker from './components/ColorPicker' - -const switchChange = (isOn: boolean) => { - console.log(isOn) -} - -const settings = [ - { - title: "Notification Collector", - description: "Uncaps the 9+ limit for notifications, showing the real number.", - modifyElement: - }, - { - title: "Lesson Alerts", - description: "Sends a native browser notification ~5 minutes prior to lessons.", - modifyElement: - }, - { - title: "Animated Background", - description: "Adds an animated background to BetterSEQTA. (May impact battery life)", - modifyElement: - }, - { - title: "Animated Background Speed", - description: "Controls the speed of the animated background.", - modifyElement: - }, - { - title: "Custom Theme Colour", - description: "Customise the overall theme colour of SEQTA Learn.", - modifyElement: - }, - { - title: "BetterSEQTA+", - description: "Unlocks premium features.", - modifyElement: - } -] - -function App() { - - return ( -
-
- - -
- {settings.map((setting, index) => ( -
-
-

{setting.title}

-

{setting.description}

-
-
- {setting.modifyElement} -
-
- ))} -
- ) -} - -export default App \ No newline at end of file diff --git a/src/popup/src/components/ColorPicker.tsx b/src/popup/src/components/ColorPicker.tsx deleted file mode 100644 index 09a11fa4..00000000 --- a/src/popup/src/components/ColorPicker.tsx +++ /dev/null @@ -1,43 +0,0 @@ -// TODO: Create types for ColorPicker -// @ts-expect-error No typescript declarations available -import ColorPicker from 'react-best-gradient-color-picker'; -import { useState, useRef, useEffect } from 'react'; - -const Picker = (): JSX.Element => { - const [color, setColor] = useState('rgba(255,20,255,1)'); - const [showPicker, setShowPicker] = useState(false); - const pickerRef = useRef(null); - - useEffect(() => { - const handleClickOutside = (event: MouseEvent): void => { - if (pickerRef.current && !pickerRef.current.contains(event.target as Node)) { - setShowPicker(false); - } - }; - - document.addEventListener('mousedown', handleClickOutside); - - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [pickerRef]); - - return ( -
- -
- { showPicker && - - } -
-
- ); -}; - -export default Picker; \ No newline at end of file diff --git a/src/popup/tailwind.config.js b/src/popup/tailwind.config.js deleted file mode 100644 index cf1ad7f8..00000000 --- a/src/popup/tailwind.config.js +++ /dev/null @@ -1,24 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: [ - "./index.html", - "./src/**/*.{js,ts,jsx,tsx}", - ], - darkMode: "class", - theme: { - extend: { - colors: { - "background-primary-dark": "", - "background-primary-light": "", - "background-secondary-dark": "", - "background-secondary-light": "", - "forground-primary-dark": "", - "forground-primary-light": "", - "forground-secondary-dark": "", - "forground-secondary-light": "" - }, - }, - }, - plugins: [], -} -