Skip to content

Commit

Permalink
Merge pull request #51 from itsmartashub/refactor/floating-btn
Browse files Browse the repository at this point in the history
Improve floating button code for better readability and maintainability #49
  • Loading branch information
itsmartashub authored Sep 15, 2024
2 parents 4ad2844 + cee9a09 commit 0ec5fd7
Show file tree
Hide file tree
Showing 12 changed files with 392 additions and 402 deletions.
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

0 comments on commit 0ec5fd7

Please sign in to comment.