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:
parent
a1ffc300ff
commit
91dd114544
|
|
@ -90,13 +90,14 @@ function ActionButton({ icon, label, active, color = "default", badge, onClick,
|
|||
<motion.button
|
||||
type="button"
|
||||
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]}
|
||||
border backdrop-blur-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
|
||||
disabled:opacity-50 disabled:cursor-not-allowed
|
||||
flex-shrink-0
|
||||
${active ? "ring-2 ring-accent/50 shadow-glow-sm" : ""}
|
||||
`}
|
||||
onClick={onClick}
|
||||
|
|
@ -106,15 +107,15 @@ function ActionButton({ icon, label, active, color = "default", badge, onClick,
|
|||
whileHover={!disabled ? "hover" : 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>}
|
||||
|
||||
{badge > 0 && (
|
||||
<motion.span
|
||||
className="absolute -top-1.5 -right-1.5 min-w-[18px] h-[18px] px-1
|
||||
rounded-full bg-red-500 text-white text-[10px] font-bold
|
||||
className="absolute -top-1 -right-1 min-w-[16px] h-[16px] px-0.5
|
||||
rounded-full bg-red-500 text-white text-[9px] font-bold
|
||||
flex items-center justify-center
|
||||
border-2 border-surface-900 shadow-lg"
|
||||
border border-surface-900 shadow-lg"
|
||||
variants={badgeVariants}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
|
|
@ -189,15 +190,15 @@ function UserChip({ authenticated, loading, username, avatarUrl, onClick }) {
|
|||
const displayUsername = useMemo(() => {
|
||||
const raw = (username || "user").toString();
|
||||
if (raw.includes("@")) return "user";
|
||||
if (raw.length <= 9) return raw;
|
||||
return raw.slice(0, 9) + "..";
|
||||
if (raw.length <= 6) return raw;
|
||||
return raw.slice(0, 6) + "..";
|
||||
}, [username]);
|
||||
|
||||
return (
|
||||
<motion.button
|
||||
type="button"
|
||||
className="flex items-center gap-2 px-2 py-1.5 rounded-full
|
||||
bg-surface-900/40 backdrop-blur-sm
|
||||
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 flex-shrink-0
|
||||
border border-surface-600/30
|
||||
hover:border-accent/50 hover:shadow-glow-sm
|
||||
transition-all duration-200"
|
||||
|
|
@ -529,8 +530,9 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
|
|||
</div>
|
||||
|
||||
{/* Right: Actions */}
|
||||
<div className="flex items-center gap-2 px-2 py-1.5 rounded-full
|
||||
bg-surface-900/50 backdrop-blur-sm border border-surface-700/30">
|
||||
<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
|
||||
flex-shrink-0 max-w-[60vw] sm:max-w-none overflow-x-auto scrollbar-hide">
|
||||
|
||||
{/* User chip */}
|
||||
<UserChip
|
||||
|
|
@ -541,17 +543,19 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
|
|||
onClick={() => authenticated && onUserIsland?.(username)}
|
||||
/>
|
||||
|
||||
{/* PWA Install */}
|
||||
{/* PWA Install - hide on very small screens */}
|
||||
{showInstallBtn && (
|
||||
<ActionButton
|
||||
icon="fa-solid fa-download"
|
||||
color="purple"
|
||||
onClick={() => promptInstall()}
|
||||
title={t('topbar.installApp')}
|
||||
/>
|
||||
<div className="hidden xs:block">
|
||||
<ActionButton
|
||||
icon="fa-solid fa-download"
|
||||
color="purple"
|
||||
onClick={() => promptInstall()}
|
||||
title={t('topbar.installApp')}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Theme - mobile */}
|
||||
{/* Theme - mobile only */}
|
||||
<div className="md:hidden" ref={themeBtnRef}>
|
||||
<ActionButton
|
||||
icon="fa-solid fa-palette"
|
||||
|
|
@ -562,11 +566,10 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
|
|||
/>
|
||||
</div>
|
||||
|
||||
{/* Language */}
|
||||
{/* Language - icon only on mobile */}
|
||||
<div ref={langBtnRef}>
|
||||
<ActionButton
|
||||
icon="fa-solid fa-globe"
|
||||
label={i18n.language?.toUpperCase().slice(0, 2)}
|
||||
color="cyan"
|
||||
active={showLangMenu}
|
||||
onClick={toggleLangMenu}
|
||||
|
|
@ -586,10 +589,9 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
|
|||
/>
|
||||
)}
|
||||
|
||||
{/* Auth */}
|
||||
{/* Auth - icon only on mobile */}
|
||||
<ActionButton
|
||||
icon={authenticated ? "fa-solid fa-right-from-bracket" : "fa-solid fa-right-to-bracket"}
|
||||
label={authenticated ? t('topbar.logout') : t('topbar.login')}
|
||||
color="green"
|
||||
onClick={() => {
|
||||
if (authenticated) { trackEvent("logout_click"); logout(); }
|
||||
|
|
|
|||
|
|
@ -1562,21 +1562,8 @@ body[data-theme="light"] .sw-modal-x{
|
|||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Entry animation for markers */
|
||||
.sw-appear {
|
||||
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; }
|
||||
/* Note: .sw-appear and .sw-appear-in are defined earlier in this file
|
||||
for .post-pin and .post-pin--simple elements. Don't override here. */
|
||||
|
||||
/* Cluster marker styles */
|
||||
.sw-cluster-marker {
|
||||
|
|
|
|||
|
|
@ -584,3 +584,32 @@ body[data-theme="light"] .text-high-contrast {
|
|||
.animate-enter-right {
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue