Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve floating button code for better readability and maintainability #51

Merged
merged 6 commits into from
Sep 15, 2024
444 changes: 58 additions & 386 deletions src/js/app/floatingBtn.js

Large diffs are not rendered by default.

153 changes: 153 additions & 0 deletions src/js/app/mainColors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import browser from 'webextension-polyfill'
import { closeSettings, $settings } from './settingsManager.js'
import { hexToHSL } from '../utils/hexToHSL.js'

const DEFAULT_COLORS = {
LIGHT: '#7e3e47',
DARK: '#ca93fb',
}

const STORAGE_KEYS = {
ACCENT_LIGHT: 'accent_light',
ACCENT_DARK: 'accent_dark',
}

let styleElement = null

const renderColorsTab = `
<section>
<div class="colorpicker-container">
<div class="colorpicker">
<input type="color" id="accentLight" value="${DEFAULT_COLORS.LIGHT}" />
<label for="accentLight">Accent <span>Light</span></label>
</div>
<div class="colorpicker">
<input type="color" id="accentDark" value="${DEFAULT_COLORS.DARK}" />
<label for="accentDark">Accent <span>Dark</span></label>
</div>
</div>
<footer class="grid mt-10">
<button id="resetAllAccents" class="btn block relative btn-primary text-center" as="button">Reset Accents</button>
</footer>
</section>
`
function handleColorInput() {
const accentLight = $settings.querySelector('#accentLight')
const accentDark = $settings.querySelector('#accentDark')

accentLight.addEventListener('input', (e) => updateCSSVars(e.target.value, null))
accentLight.addEventListener('change', (e) => {
setAccentToStorage(STORAGE_KEYS.ACCENT_LIGHT, e.target.value)
closeSettings()
})

accentDark.addEventListener('input', (e) => updateCSSVars(null, e.target.value))
accentDark.addEventListener('change', (e) => {
setAccentToStorage(STORAGE_KEYS.ACCENT_DARK, e.target.value)
closeSettings()
})
}

function updateCSSVars(lightColor, darkColor) {
if (!styleElement) injectStyleElement()

const lightHSL = hexToHSL(lightColor || $settings.querySelector('#accentLight').value)
const darkHSL = hexToHSL(darkColor || $settings.querySelector('#accentDark').value)

const cssVars = `
html.light {
--accent-h: ${lightHSL[0]} !important;
--accent-s: ${lightHSL[1]}% !important;
--accent-l: ${lightHSL[2]}% !important;
}
html.dark {
--accent-h: ${darkHSL[0]} !important;
--accent-s: ${darkHSL[1]}% !important;
--accent-l: ${darkHSL[2]}% !important;
}
`

styleElement.textContent = cssVars
}

function injectStyleElement() {
styleElement = document.createElement('style')
styleElement.type = 'text/css'
document.head.appendChild(styleElement)
}

// Storage management
async function setAccentToStorage(storageColorProperty, accentValue) {
try {
await browser.storage.sync.set({ [storageColorProperty]: accentValue })
} catch (e) {
console.error('Error setting the accent colors in storage:', e)
}
}

function setColorInputValue({ accentLight, accentDark }) {
$settings.querySelector('#accentLight').value = accentLight
$settings.querySelector('#accentDark').value = accentDark
}

async function handleAccentsStorage() {
try {
const { [STORAGE_KEYS.ACCENT_LIGHT]: accentLight, [STORAGE_KEYS.ACCENT_DARK]: accentDark } =
await browser.storage.sync.get([STORAGE_KEYS.ACCENT_LIGHT, STORAGE_KEYS.ACCENT_DARK])

if (!accentLight || !accentDark) {
await browser.storage.sync.set({
[STORAGE_KEYS.ACCENT_LIGHT]: DEFAULT_COLORS.LIGHT,
[STORAGE_KEYS.ACCENT_DARK]: DEFAULT_COLORS.DARK,
})
}

const accentColorLight = accentLight || DEFAULT_COLORS.LIGHT
const accentColorDark = accentDark || DEFAULT_COLORS.DARK

updateCSSVars(accentColorLight, accentColorDark)
setColorInputValue({ accentLight: accentColorLight, accentDark: accentColorDark })
} catch (error) {
console.error('Error handling accent colors:', error)
}
}

async function resetAllAccents() {
if (!styleElement) injectStyleElement()

const accentLight = hexToHSL(DEFAULT_COLORS.LIGHT)
const accentDark = hexToHSL(DEFAULT_COLORS.DARK)

const cssVars = `
html.light {
--accent-h: ${accentLight[0]} !important;
--accent-s: ${accentLight[1]}% !important;
--accent-l: ${accentLight[2]}% !important;
}
html.dark {
--accent-h: ${accentDark[0]} !important;
--accent-s: ${accentDark[1]}% !important;
--accent-l: ${accentDark[2]}% !important;
}
`

styleElement.textContent = cssVars

setColorInputValue({ accentLight: DEFAULT_COLORS.LIGHT, accentDark: DEFAULT_COLORS.DARK })

await browser.storage.sync.set({
[STORAGE_KEYS.ACCENT_LIGHT]: DEFAULT_COLORS.LIGHT,
[STORAGE_KEYS.ACCENT_DARK]: DEFAULT_COLORS.DARK,
})
}

const init = async () => {
try {
await handleAccentsStorage()
handleColorInput()
} catch (error) {
console.error('Initialization error:', error)
}
}

export { renderColorsTab, resetAllAccents, init }
8 changes: 5 additions & 3 deletions src/js/app/mainFonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const letterSpacingData = {
}

// HTML template for font changer popover
export let fontHtmlCode = `
let renderFontsTab = `
<section id="fontChangerPopover" class="fonts">
<div class="fonts__props">
<div class="fonts__family fonts__group card card--big h-full">
Expand Down Expand Up @@ -331,7 +331,7 @@ function resetFonts() {
}

// Function to handle font listeners
export function handleFontsListeners() {
function handleFontsListeners() {
const selectors = {
selectFontFamily: document.querySelector('.gpth-settings #fontFamily'),
inputFontSize: document.querySelector('.gpth-settings #fontSize'),
Expand Down Expand Up @@ -385,4 +385,6 @@ function init() {
// Load settings on page load
loadSettings()
}
init()

export { init, renderFontsTab, handleFontsListeners }
// init()
8 changes: 4 additions & 4 deletions src/js/app/mainAssets.js → src/js/app/mainWidths.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ const addResizeListener = () => {
} */

// Event listeners
const handleAssetsListeners = () => {
const handleWidthsListeners = () => {
document.querySelector('.gpth-settings #gpth-full-width')?.addEventListener('change', toggleChatFullWidth)

document
Expand All @@ -291,7 +291,7 @@ const handleAssetsListeners = () => {
}

// HTML template
const assetsHtmlCode = `
const renderWidthsTab = `
<section id="sectionAssets" class="gpth-assets">
<div class="gpth-assets__custom-width mb-4">
${renderSmallCardOption({
Expand Down Expand Up @@ -345,7 +345,7 @@ const init = () => {
loadSettings()
}

export { assetsHtmlCode, handleAssetsListeners, init }
export { renderWidthsTab, handleWidthsListeners, init }

/* // ? =============== DEV ONLY fn ===============
const assetsStorageKeys = Object.keys(CONFIG.FW_DEFAULTS) // ? DEV ONLY var - Get the keys from FW_DEFAULTS object
Expand Down Expand Up @@ -379,4 +379,4 @@ const init = () => {
// getAllStorageItems()
getAllStorageItems(assetsStorageKeys)
}
export { assetsHtmlCode, handleAssetsListeners, init } */
export { renderAssetsTab, handleAssetsListeners, init } */
88 changes: 88 additions & 0 deletions src/js/app/settingsManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { renderColorsTab, resetAllAccents } from './mainColors.js'
import { renderFontsTab, handleFontsListeners } from './mainFonts.js'
import { renderWidthsTab, handleWidthsListeners } from './mainWidths.js'

let $settings = null
let $resetAllAccentsBtn = null

const SETTINGS_OPEN_CLASS = 'gpth-settings--open'

async function createSettings() {
const gpthSettings = document.createElement('div')
gpthSettings.className = 'gpth-settings fixed flex flex-col'

gpthSettings.innerHTML = `
<header class="mb-5">
<h2 class="mt-5 text-center font-medium gpth-settings__title"><span class="font-semibold">GPThemes</span> Customization</h2>
<button class="text-token-text-tertiary hover:text-token-text-primary absolute top-4 right-4" id="gpth-settings-close">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6.34315 6.34338L17.6569 17.6571M17.6569 6.34338L6.34315 17.6571" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></svg>
</button>
</header>
<main>
<div class="tabs">
<div class="tab-buttons flex items-center rounded-full p-1 font-semibold mb-10">
<button class="tab-button py-2 px-4 focus:outline-none text-center rounded-full active">Color</button>
<button class="tab-button py-2 px-4 focus:outline-none text-center rounded-full">Font</button>
<button class="tab-button py-2 px-4 focus:outline-none text-center rounded-full">Width</button>
</div>
<div class="tab-content">
<div class="tab-pane active" id="tab-colors">${renderColorsTab}</div>
<div class="tab-pane hidden" id="tab-fonts">${renderFontsTab}</div>
<div class="tab-pane hidden" id="tab-assets">${renderWidthsTab}</div>
</div>
</div>
</main>
`

document.body.appendChild(gpthSettings)
cacheElements(gpthSettings)
addListeners()
}

function cacheElements(gpthSettings) {
$settings = gpthSettings
$resetAllAccentsBtn = $settings.querySelector('#resetAllAccents')
$resetAllAccentsBtn.disabled = true
}
function addListeners() {
document.getElementById('gpth-settings-close').addEventListener('click', closeSettings)
handleTabsSwitching()
handleFontsListeners()
handleWidthsListeners()
$resetAllAccentsBtn.addEventListener('click', resetAllAccents)
}
// ___ Settings management
function openSettings() {
$settings.classList.add(SETTINGS_OPEN_CLASS)
$settings.addEventListener('transitionend', handleSettingsOpened)
$resetAllAccentsBtn.disabled = false
}
function handleSettingsOpened() {
document.body.addEventListener('click', handleClickOutsideSettings)
$settings.removeEventListener('transitionend', handleSettingsOpened)
}
function closeSettings() {
$settings.classList.remove(SETTINGS_OPEN_CLASS)
document.body.removeEventListener('click', handleClickOutsideSettings)
$resetAllAccentsBtn.disabled = true
}
function handleClickOutsideSettings(e) {
if (!$settings.contains(e.target) && e.target.id !== 'gpth-open-settings') closeSettings()
}

function handleTabsSwitching() {
const tabs = document.querySelectorAll('.gpth-settings .tab-button')
const panes = document.querySelectorAll('.gpth-settings .tab-pane')

tabs.forEach((tab, index) => {
tab.addEventListener('click', () => {
document.querySelector('.tab-button.active').classList.remove('active')
document.querySelector('.tab-pane:not(.hidden)').classList.add('hidden')

tab.classList.add('active')
panes[index].classList.remove('hidden')
})
})
}

export { createSettings, openSettings, closeSettings, $settings }
68 changes: 68 additions & 0 deletions src/js/app/themeManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import browser from 'webextension-polyfill'
import { closeFloatingOptions } from './floatingBtn.js'
import { openSettings } from './settingsManager.js'

const THEMES = {
LIGHT: 'light',
DARK: 'dark',
OLED: 'oled',
}

const STORAGE_KEYS = {
THEME: 'gptheme',
}

let htmlTag = document.documentElement

async function initTheme() {
try {
const { [STORAGE_KEYS.THEME]: storedTheme } = await browser.storage.sync.get(STORAGE_KEYS.THEME)

// console.log({ storedTheme })

const theme =
storedTheme || (window.matchMedia('(prefers-color-scheme: light)').matches ? THEMES.LIGHT : THEMES.DARK)
applyTheme(theme)
} catch (error) {
console.error('Error initializing theme:', error)
}
}
async function setTheme(theme) {
try {
await browser.storage.sync.set({ [STORAGE_KEYS.THEME]: theme })
applyTheme(theme)
closeFloatingOptions()
} catch (error) {
console.error('Error setting theme:', error)
}
}
function applyTheme(theme) {
console.log('Applying theme:', theme)

htmlTag.dataset.gptheme = theme === THEMES.OLED ? theme : ''
htmlTag.style.colorScheme = theme === THEMES.OLED ? THEMES.DARK : theme
htmlTag.className = theme === THEMES.OLED ? THEMES.DARK : theme
}
function handleChangeTheme(e) {
const themeButton = e.target.closest('button')
if (!themeButton) return

const themeButtonID = themeButton.id // light | dark | oled | gpth-open-settings

console.log({ themeButtonID })

if (themeButtonID === THEMES.LIGHT || themeButtonID === THEMES.DARK || themeButtonID === THEMES.OLED) {
setTheme(themeButtonID)
return
}

/* If clicked on "⚙️ Open Settings" */
if (themeButtonID === 'gpth-open-settings') {
openSettings()
}
}
const init = () => {
initTheme()
}

export { init, handleChangeTheme }
14 changes: 10 additions & 4 deletions src/js/content.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import './app/floatingBtn'
import './app/mainFonts'
import { init as initAssets } from './app/mainAssets'
import { init as initThemes } from './app/themeManager'
import { init as initFloating } from './app/floatingBtn'
import { init as initColors } from './app/mainColors'
import { init as initFonts } from './app/mainFonts'
import { init as initWidths } from './app/mainWidths'

initAssets()
initThemes()
initFloating()
initColors()
initFonts()
initWidths()
2 changes: 1 addition & 1 deletion src/manifests/chromium-mv3/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"matches": ["https://chat.openai.com/*", "https://chatgpt.com/*"],
"js": ["../../js/content.js"],
"css": ["../../sass/index.scss"],
"run_at": "document_end"
"run_at": "document_idle"
}
],
"background": {
Expand Down
Loading