-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51 from itsmartashub/refactor/floating-btn
Improve floating button code for better readability and maintainability #49
- Loading branch information
Showing
12 changed files
with
392 additions
and
402 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.