Polish mobile emoji catalog and detail navigation

This commit is contained in:
Dwindi Ramadhana
2026-02-22 00:16:13 +07:00
parent e8e2daccfe
commit 638e1d5b20
2 changed files with 70 additions and 11 deletions

View File

@@ -89,6 +89,9 @@
<div class="sticky top-0 z-40 -mx-4 px-4 py-3 mb-6 bg-[var(--app-bg)]/90 backdrop-blur border-b border-white/10 sm:static sm:mx-0 sm:px-0 sm:py-0 sm:mb-8 sm:border-0">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2 text-xs sm:text-sm text-gray-500 font-mono">
<button type="button" onclick="window.history.length > 1 ? window.history.back() : (window.location.href='{{ route('home') }}')" class="inline-flex sm:hidden w-8 h-8 rounded-full bg-white/5 border border-white/10 items-center justify-center text-gray-300 hover:text-white">
<i data-lucide="arrow-left" class="w-4 h-4"></i>
</button>
<a href="{{ route('home') }}" class="hover:text-white transition-colors">Home</a>
<i data-lucide="chevron-right" class="w-3 h-3"></i>
<span class="hidden sm:inline-flex hover:text-white">{{ $category }}</span>

View File

@@ -10,6 +10,19 @@
--emoji-size: 2rem;
grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr));
}
#grid[data-hide-labels="1"] .emoji-card {
border-color: rgba(255, 255, 255, 0.06);
}
#grid[data-hide-labels="1"] .emoji-card-copy {
opacity: 0;
transform: translateY(-2px);
transition: all 150ms ease;
}
#grid[data-hide-labels="1"] .emoji-card:hover .emoji-card-copy,
#grid[data-hide-labels="1"] .emoji-card:focus-within .emoji-card-copy {
opacity: 1;
transform: translateY(0);
}
@media (max-width: 640px) {
#grid {
--card-min: 0px;
@@ -119,7 +132,7 @@
</div>
<div class="flex flex-wrap items-center gap-2 justify-between">
<div class="flex flex-wrap gap-2">
<div class="hidden sm:flex flex-wrap gap-2">
<button data-tag="happy" class="quick-tag px-2 py-1 bg-white/5 hover:bg-brand-ocean/20 hover:text-brand-oceanSoft border border-white/5 rounded text-[11px] transition-colors">#happy</button>
<button data-tag="love" class="quick-tag px-2 py-1 bg-white/5 hover:bg-brand-ocean/20 hover:text-brand-oceanSoft border border-white/5 rounded text-[11px] transition-colors">#love</button>
<button data-tag="party" class="quick-tag px-2 py-1 bg-white/5 hover:bg-brand-ocean/20 hover:text-brand-oceanSoft border border-white/5 rounded text-[11px] transition-colors">#party</button>
@@ -134,7 +147,7 @@
<div class="flex-1 overflow-y-auto p-4 sm:p-6 pb-24 lg:pb-6">
<div class="w-full">
<div id="hero-cards" class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-4 mb-6 transition-all duration-300">
<section id="hero-main" class="md:col-span-2 glass-card rounded-2xl p-6 relative overflow-hidden min-h-[180px] flex flex-col justify-end transition-all duration-300">
<section id="hero-main" class="hidden md:flex md:col-span-2 glass-card rounded-2xl p-6 relative overflow-hidden min-h-[180px] flex-col justify-end transition-all duration-300">
<div class="absolute top-0 right-0 p-5 opacity-50">
<i data-lucide="sparkles" class="w-5 h-5 text-brand-sun"></i>
</div>
@@ -171,6 +184,13 @@
<div class="flex items-center gap-2 mb-4 px-1">
<h4 class="font-bold text-gray-200">All Emojis</h4>
<div class="h-px bg-white/10 flex-1"></div>
<button id="labels-toggle" class="h-8 rounded-md bg-white/5 hover:bg-white/10 border border-white/10 px-2 text-[11px] text-gray-300">
Labels: Off
</button>
<div class="flex sm:hidden items-center gap-1 text-[11px] text-gray-400">
<button id="grid-smaller-mobile" class="w-8 h-8 rounded-md bg-white/5 hover:bg-white/10 border border-white/10">-</button>
<button id="grid-bigger-mobile" class="w-8 h-8 rounded-md bg-white/5 hover:bg-white/10 border border-white/10">+</button>
</div>
<div class="hidden sm:flex items-center gap-2 text-[11px] text-gray-400">
<button id="grid-smaller" class="w-7 h-7 rounded-md bg-white/5 hover:bg-white/10 border border-white/10">-</button>
<input id="grid-size" type="range" min="0" max="2" step="1" value="1" class="w-20 accent-[#2053ff]">
@@ -259,7 +279,11 @@
const gridSizeEl = document.getElementById('grid-size');
const gridSmallerEl = document.getElementById('grid-smaller');
const gridBiggerEl = document.getElementById('grid-bigger');
const gridSmallerMobileEl = document.getElementById('grid-smaller-mobile');
const gridBiggerMobileEl = document.getElementById('grid-bigger-mobile');
const labelsToggleEl = document.getElementById('labels-toggle');
const densityStorageKey = 'dewemoji_grid_density';
const labelsStorageKey = 'dewemoji_grid_show_labels';
const csrf = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
const keywordEditModal = document.getElementById('keyword-edit-modal');
const keywordEditClose = document.getElementById('keyword-edit-close');
@@ -296,6 +320,16 @@
dark: 4,
};
function isLabelsEnabled() {
return localStorage.getItem(labelsStorageKey) === '1';
}
function applyLabelsToggleUI() {
const enabled = isLabelsEnabled();
grid.dataset.hideLabels = enabled ? '0' : '1';
if (labelsToggleEl) labelsToggleEl.textContent = `Labels: ${enabled ? 'On' : 'Off'}`;
}
if (initialQuery) qEl.value = initialQuery;
function slugify(text) {
@@ -558,19 +592,27 @@
return;
}
const showLabels = isLabelsEnabled();
items.forEach((item) => {
const renderedEmoji = emojiWithTone(item);
const card = document.createElement('div');
card.className = 'emoji-card relative aspect-square rounded-lg bg-white/5 hover:bg-white/10 transition-transform hover:scale-[1.02] border border-transparent hover:border-white/20 overflow-hidden group';
card.innerHTML = `
<a href="/emoji/${encodeURIComponent(item.slug)}" class="absolute inset-0 flex items-center justify-center pb-10">
<span class="leading-none" style="font-size:var(--emoji-size)">${esc(renderedEmoji)}</span>
</a>
<div class="emoji-card-bar absolute bottom-0 left-0 right-0 border-t border-white/10 bg-black/20 px-2 py-1.5 flex items-start gap-1">
<span class="emoji-name-clamp text-[10px] text-gray-300 text-left flex-1">${esc(item.name)}</span>
<button type="button" class="copy-btn shrink-0 w-6 h-6 rounded bg-white/10 hover:bg-brand-ocean/30 text-[11px] text-gray-200 hover:text-white transition-colors" title="Copy emoji"></button>
</div>
`;
card.innerHTML = showLabels
? `
<a href="/emoji/${encodeURIComponent(item.slug)}" class="absolute inset-0 flex items-center justify-center pb-10">
<span class="leading-none" style="font-size:var(--emoji-size)">${esc(renderedEmoji)}</span>
</a>
<div class="emoji-card-bar absolute bottom-0 left-0 right-0 border-t border-white/10 bg-black/20 px-2 py-1.5 flex items-start gap-1">
<span class="emoji-name-clamp text-[10px] text-gray-300 text-left flex-1">${esc(item.name)}</span>
<button type="button" class="copy-btn shrink-0 w-6 h-6 rounded bg-white/10 hover:bg-brand-ocean/30 text-[11px] text-gray-200 hover:text-white transition-colors" title="Copy emoji"></button>
</div>
`
: `
<a href="/emoji/${encodeURIComponent(item.slug)}" class="absolute inset-0 flex items-center justify-center">
<span class="leading-none" style="font-size:var(--emoji-size)">${esc(renderedEmoji)}</span>
</a>
<button type="button" class="copy-btn emoji-card-copy absolute top-1.5 right-1.5 w-7 h-7 rounded bg-black/35 hover:bg-brand-ocean/40 border border-white/20 text-[11px] text-gray-100 hover:text-white transition-colors" title="Copy emoji"></button>
`;
const copyBtn = card.querySelector('.copy-btn');
if (copyBtn) {
copyBtn.addEventListener('click', (e) => {
@@ -704,8 +746,22 @@
gridSmallerEl.addEventListener('click', () => applyGridDensity(Number(gridSizeEl.value) - 1));
gridBiggerEl.addEventListener('click', () => applyGridDensity(Number(gridSizeEl.value) + 1));
}
gridSmallerMobileEl?.addEventListener('click', () => {
const base = Number(localStorage.getItem(densityStorageKey) ?? gridSizeEl?.value ?? 1);
applyGridDensity(base - 1);
});
gridBiggerMobileEl?.addEventListener('click', () => {
const base = Number(localStorage.getItem(densityStorageKey) ?? gridSizeEl?.value ?? 1);
applyGridDensity(base + 1);
});
labelsToggleEl?.addEventListener('click', () => {
localStorage.setItem(labelsStorageKey, isLabelsEnabled() ? '0' : '1');
applyLabelsToggleUI();
fetchEmojis(true);
});
(async () => {
applyLabelsToggleUI();
setToneControlValue(localStorage.getItem(toneStorageKey) || 'off');
await loadCategories();
if (initialCategory && state.categories[initialCategory]) {