Refine mobile tone/theme controls in discover header

This commit is contained in:
Dwindi Ramadhana
2026-02-18 23:52:00 +07:00
parent 0d239b1967
commit d9f326d1d6

View File

@@ -83,8 +83,14 @@
<i data-lucide="search" class="w-5 h-5"></i>
</div>
<input id="q" type="text" placeholder="Search emojis by keyword, mood, meaning..." class="w-full bg-transparent text-white placeholder-gray-500 focus:outline-none font-medium h-full text-sm sm:text-base">
<div class="hidden md:flex items-center pr-3">
<kbd class="hidden sm:inline-block px-2 py-0.5 text-[10px] font-mono text-gray-500 bg-white/5 border border-white/10 rounded-md">⌘K</kbd>
<div class="flex md:hidden items-center gap-2 pr-2">
<button id="tone-toggle-mobile" class="w-8 h-8 rounded-full theme-surface border border-white/10 flex items-center justify-center text-gray-300 hover:text-white transition-colors shrink-0" title="Tone: Default">
<span id="tone-dot-mobile" class="w-3 h-3 rounded-full bg-white/80 border border-white/30"></span>
</button>
<button id="theme-toggle-mobile" class="w-8 h-8 rounded-full theme-surface border border-white/10 flex items-center justify-center text-gray-300 hover:text-white transition-colors shrink-0">
<span class="sr-only">Toggle theme</span>
<i data-lucide="sun-moon" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
@@ -96,15 +102,10 @@
<select id="subcategory" class="bg-[#151518] border border-white/10 rounded-xl px-4 text-sm text-gray-300 focus:outline-none focus:border-brand-ocean hover:bg-white/5 transition-colors h-11 cursor-pointer appearance-none theme-surface" disabled>
<option value="">All Subcategories</option>
</select>
<select id="skin-tone" class="bg-[#151518] border border-white/10 rounded-xl px-4 text-sm text-gray-300 focus:outline-none focus:border-brand-ocean hover:bg-white/5 transition-colors h-11 cursor-pointer appearance-none theme-surface">
<option value="off">Default tone</option>
<option value="light">Light</option>
<option value="medium-light">Medium light</option>
<option value="medium">Medium</option>
<option value="medium-dark">Medium dark</option>
<option value="dark">Dark</option>
</select>
<button id="theme-toggle" class="w-10 h-10 rounded-full theme-surface border border-white/10 shadow-lg flex items-center justify-center text-gray-300 hover:text-white transition-colors">
<button id="tone-toggle" class="hidden md:flex w-10 h-10 rounded-full theme-surface border border-white/10 shadow-lg items-center justify-center text-gray-300 hover:text-white transition-colors" title="Tone: Default">
<span id="tone-dot-desktop" class="w-4 h-4 rounded-full bg-white/80 border border-white/30"></span>
</button>
<button id="theme-toggle" class="hidden md:flex w-10 h-10 rounded-full theme-surface border border-white/10 shadow-lg items-center justify-center text-gray-300 hover:text-white transition-colors">
<span class="sr-only">Toggle theme</span>
<i data-lucide="moon" class="w-4 h-4" data-theme-icon="dark"></i>
<i data-lucide="sun" class="w-4 h-4 hidden" data-theme-icon="light"></i>
@@ -234,7 +235,12 @@
const qEl = document.getElementById('q');
const catEl = document.getElementById('category');
const subEl = document.getElementById('subcategory');
const toneEl = document.getElementById('skin-tone');
const toneDesktopBtn = document.getElementById('tone-toggle');
const toneMobileBtn = document.getElementById('tone-toggle-mobile');
const toneDotDesktop = document.getElementById('tone-dot-desktop');
const toneDotMobile = document.getElementById('tone-dot-mobile');
const themeMobileBtn = document.getElementById('theme-toggle-mobile');
const themeDesktopBtn = document.getElementById('theme-toggle');
const grid = document.getElementById('grid');
const count = document.getElementById('count');
const more = document.getElementById('more');
@@ -260,6 +266,24 @@
const keywordEditText = document.getElementById('keyword-edit-text');
const keywordEditLang = document.getElementById('keyword-edit-lang');
const toneStorageKey = 'dewemoji_skin_tone';
const toneOrder = ['off', 'light', 'medium-light', 'medium', 'medium-dark', 'dark'];
const toneLabelMap = {
off: 'Default',
light: 'Light',
'medium-light': 'Medium light',
medium: 'Medium',
'medium-dark': 'Medium dark',
dark: 'Dark',
};
const toneColorMap = {
off: '#ffd155',
light: '#f6d7c3',
'medium-light': '#e8bc95',
medium: '#c68a62',
'medium-dark': '#8f5f45',
dark: '#5b3b2f',
};
let currentTone = 'off';
const toneIndexMap = {
light: 0,
'medium-light': 1,
@@ -328,7 +352,23 @@
}
function selectedTone() {
return String(toneEl?.value || 'off');
return currentTone;
}
function setToneControlValue(value) {
const normalized = toneOrder.includes(String(value)) ? String(value) : 'off';
currentTone = normalized;
const bg = toneColorMap[normalized] || toneColorMap.off;
const title = `Tone: ${toneLabelMap[normalized] || 'Default'}`;
[toneDotDesktop, toneDotMobile].forEach((dot) => {
if (!dot) return;
dot.style.backgroundColor = bg;
});
[toneDesktopBtn, toneMobileBtn].forEach((btn) => {
if (!btn) return;
btn.title = title;
btn.setAttribute('aria-label', title);
});
}
function emojiWithTone(item) {
@@ -568,9 +608,27 @@
});
subEl.addEventListener('change', () => fetchEmojis(true));
toneEl?.addEventListener('change', () => {
localStorage.setItem(toneStorageKey, selectedTone());
const onToneChange = (nextTone = null) => {
const tone = nextTone || selectedTone();
setToneControlValue(tone);
localStorage.setItem(toneStorageKey, tone);
fetchEmojis(true);
};
const cycleTone = () => {
const idx = toneOrder.indexOf(selectedTone());
const next = toneOrder[(idx + 1) % toneOrder.length];
onToneChange(next);
};
toneDesktopBtn?.addEventListener('click', cycleTone);
toneMobileBtn?.addEventListener('click', cycleTone);
themeMobileBtn?.addEventListener('click', () => {
themeDesktopBtn?.click();
});
// keep mobile icon synced when desktop toggle flips theme
themeDesktopBtn?.addEventListener('click', () => {
setTimeout(() => lucide.createIcons(), 0);
});
more.addEventListener('click', async () => {
@@ -644,9 +702,7 @@
}
(async () => {
if (toneEl) {
toneEl.value = localStorage.getItem(toneStorageKey) || 'off';
}
setToneControlValue(localStorage.getItem(toneStorageKey) || 'off');
await loadCategories();
if (initialCategory && state.categories[initialCategory]) {
catEl.value = initialCategory;