fix: TopBar mobile compact + map markers positioning

- Make TopBar buttons smaller on mobile (icon-only)
- Remove language label on mobile, reduce padding/gaps
- Add scrollbar-hide utility for clean overflow
- Fix marker CSS conflict that broke positioning
- Remove conflicting .sw-appear animation that overrode marker styles

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-01-19 09:27:22 +00:00
parent a1ffc300ff
commit 91dd114544
3 changed files with 57 additions and 39 deletions

View File

@ -90,13 +90,14 @@ function ActionButton({ icon, label, active, color = "default", badge, onClick,
<motion.button <motion.button
type="button" type="button"
className={` className={`
relative h-8 px-3 rounded-full relative h-7 w-7 sm:h-8 sm:w-auto sm:px-3 rounded-full
bg-gradient-to-br ${colorClasses[color]} bg-gradient-to-br ${colorClasses[color]}
border backdrop-blur-sm border backdrop-blur-sm
font-semibold text-sm font-semibold text-sm
inline-flex items-center justify-center gap-2 inline-flex items-center justify-center gap-1.5
transition-colors duration-200 transition-colors duration-200
disabled:opacity-50 disabled:cursor-not-allowed disabled:opacity-50 disabled:cursor-not-allowed
flex-shrink-0
${active ? "ring-2 ring-accent/50 shadow-glow-sm" : ""} ${active ? "ring-2 ring-accent/50 shadow-glow-sm" : ""}
`} `}
onClick={onClick} onClick={onClick}
@ -106,15 +107,15 @@ function ActionButton({ icon, label, active, color = "default", badge, onClick,
whileHover={!disabled ? "hover" : undefined} whileHover={!disabled ? "hover" : undefined}
whileTap={!disabled ? "tap" : undefined} whileTap={!disabled ? "tap" : undefined}
> >
<i className={`${icon} text-sm`} /> <i className={`${icon} text-xs sm:text-sm`} />
{label && <span className="hidden sm:inline text-xs">{label}</span>} {label && <span className="hidden sm:inline text-xs">{label}</span>}
{badge > 0 && ( {badge > 0 && (
<motion.span <motion.span
className="absolute -top-1.5 -right-1.5 min-w-[18px] h-[18px] px-1 className="absolute -top-1 -right-1 min-w-[16px] h-[16px] px-0.5
rounded-full bg-red-500 text-white text-[10px] font-bold rounded-full bg-red-500 text-white text-[9px] font-bold
flex items-center justify-center flex items-center justify-center
border-2 border-surface-900 shadow-lg" border border-surface-900 shadow-lg"
variants={badgeVariants} variants={badgeVariants}
initial="initial" initial="initial"
animate="animate" animate="animate"
@ -189,15 +190,15 @@ function UserChip({ authenticated, loading, username, avatarUrl, onClick }) {
const displayUsername = useMemo(() => { const displayUsername = useMemo(() => {
const raw = (username || "user").toString(); const raw = (username || "user").toString();
if (raw.includes("@")) return "user"; if (raw.includes("@")) return "user";
if (raw.length <= 9) return raw; if (raw.length <= 6) return raw;
return raw.slice(0, 9) + ".."; return raw.slice(0, 6) + "..";
}, [username]); }, [username]);
return ( return (
<motion.button <motion.button
type="button" type="button"
className="flex items-center gap-2 px-2 py-1.5 rounded-full className="flex items-center gap-1 sm:gap-2 px-1.5 sm:px-2 py-1 sm:py-1.5 rounded-full
bg-surface-900/40 backdrop-blur-sm bg-surface-900/40 backdrop-blur-sm flex-shrink-0
border border-surface-600/30 border border-surface-600/30
hover:border-accent/50 hover:shadow-glow-sm hover:border-accent/50 hover:shadow-glow-sm
transition-all duration-200" transition-all duration-200"
@ -529,8 +530,9 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
</div> </div>
{/* Right: Actions */} {/* Right: Actions */}
<div className="flex items-center gap-2 px-2 py-1.5 rounded-full <div className="flex items-center gap-1 sm:gap-2 px-1 sm:px-2 py-1 sm:py-1.5 rounded-full
bg-surface-900/50 backdrop-blur-sm border border-surface-700/30"> bg-surface-900/50 backdrop-blur-sm border border-surface-700/30
flex-shrink-0 max-w-[60vw] sm:max-w-none overflow-x-auto scrollbar-hide">
{/* User chip */} {/* User chip */}
<UserChip <UserChip
@ -541,17 +543,19 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
onClick={() => authenticated && onUserIsland?.(username)} onClick={() => authenticated && onUserIsland?.(username)}
/> />
{/* PWA Install */} {/* PWA Install - hide on very small screens */}
{showInstallBtn && ( {showInstallBtn && (
<ActionButton <div className="hidden xs:block">
icon="fa-solid fa-download" <ActionButton
color="purple" icon="fa-solid fa-download"
onClick={() => promptInstall()} color="purple"
title={t('topbar.installApp')} onClick={() => promptInstall()}
/> title={t('topbar.installApp')}
/>
</div>
)} )}
{/* Theme - mobile */} {/* Theme - mobile only */}
<div className="md:hidden" ref={themeBtnRef}> <div className="md:hidden" ref={themeBtnRef}>
<ActionButton <ActionButton
icon="fa-solid fa-palette" icon="fa-solid fa-palette"
@ -562,11 +566,10 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
/> />
</div> </div>
{/* Language */} {/* Language - icon only on mobile */}
<div ref={langBtnRef}> <div ref={langBtnRef}>
<ActionButton <ActionButton
icon="fa-solid fa-globe" icon="fa-solid fa-globe"
label={i18n.language?.toUpperCase().slice(0, 2)}
color="cyan" color="cyan"
active={showLangMenu} active={showLangMenu}
onClick={toggleLangMenu} onClick={toggleLangMenu}
@ -586,10 +589,9 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
/> />
)} )}
{/* Auth */} {/* Auth - icon only on mobile */}
<ActionButton <ActionButton
icon={authenticated ? "fa-solid fa-right-from-bracket" : "fa-solid fa-right-to-bracket"} icon={authenticated ? "fa-solid fa-right-from-bracket" : "fa-solid fa-right-to-bracket"}
label={authenticated ? t('topbar.logout') : t('topbar.login')}
color="green" color="green"
onClick={() => { onClick={() => {
if (authenticated) { trackEvent("logout_click"); logout(); } if (authenticated) { trackEvent("logout_click"); logout(); }

View File

@ -1562,21 +1562,8 @@ body[data-theme="light"] .sw-modal-x{
pointer-events: auto; pointer-events: auto;
} }
/* Entry animation for markers */ /* Note: .sw-appear and .sw-appear-in are defined earlier in this file
.sw-appear { for .post-pin and .post-pin--simple elements. Don't override here. */
opacity: 0;
animation: markerFadeSlide 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.sw-appear-in {
opacity: 1;
}
/* Stagger effect for multiple markers */
.sw-appear:nth-child(2) { animation-delay: 0.05s; }
.sw-appear:nth-child(3) { animation-delay: 0.1s; }
.sw-appear:nth-child(4) { animation-delay: 0.15s; }
.sw-appear:nth-child(5) { animation-delay: 0.2s; }
/* Cluster marker styles */ /* Cluster marker styles */
.sw-cluster-marker { .sw-cluster-marker {

View File

@ -584,3 +584,32 @@ body[data-theme="light"] .text-high-contrast {
.animate-enter-right { .animate-enter-right {
animation: enterFromRight 0.4s cubic-bezier(0.16, 1, 0.3, 1); animation: enterFromRight 0.4s cubic-bezier(0.16, 1, 0.3, 1);
} }
/*
Scrollbar Utilities
*/
/* Hide scrollbar but keep functionality */
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
/* Thin scrollbar */
.scrollbar-thin {
scrollbar-width: thin;
}
.scrollbar-thin::-webkit-scrollbar {
width: 4px;
height: 4px;
}
.scrollbar-thin::-webkit-scrollbar-thumb {
background: rgba(96, 165, 250, 0.3);
border-radius: 2px;
}