Improve FAB menu: z-index, labels, clear all filters

- Fix z-index so FAB items appear above weather widget
- Add X button to clear all filters when FAB is open
- Add text labels for categories and subcategories
- Make labels readable with dark text on light background
- Update backdrop z-index hierarchy

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Sociowire Dev 2026-01-12 04:59:32 +00:00
parent 8e3f8c4859
commit 74ab0bd1f5
3 changed files with 88 additions and 30 deletions

View File

@ -2007,6 +2007,10 @@ export default function MapView({
onSubcategoryToggle={handleSubcategoryToggle} onSubcategoryToggle={handleSubcategoryToggle}
onTime={(h) => setTimeHours(h)} onTime={(h) => setTimeHours(h)}
onWeather={() => setWeatherViewEnabled((prev) => !prev)} onWeather={() => setWeatherViewEnabled((prev) => !prev)}
onClearAllFilters={() => {
setMainFilters([]);
setSubFilters([]);
}}
activeCategories={mainFilters} activeCategories={mainFilters}
activeSubcategories={subFilters} activeSubcategories={subFilters}
activeTime={timeHours} activeTime={timeHours}

View File

@ -7,7 +7,7 @@
background: rgba(0, 0, 0, 0.15); background: rgba(0, 0, 0, 0.15);
backdrop-filter: blur(2px); backdrop-filter: blur(2px);
-webkit-backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
z-index: 398; /* Below search dropdown (500) */ z-index: 440; /* Above weather widget (300), below FAB items */
animation: fab-fade-in 0.2s ease; animation: fab-fade-in 0.2s ease;
} }
@ -21,7 +21,7 @@
.fab-right { .fab-right {
position: fixed; position: fixed;
top: 180px; top: 180px;
z-index: 399; /* Below search dropdown (500) */ z-index: 450; /* Above weather widget (300), below search dropdown (500) */
} }
.fab-left { .fab-left {
@ -46,10 +46,10 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
transition: transform 0.2s ease, box-shadow 0.2s ease; transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
position: relative; position: relative;
z-index: 400; /* Below search dropdown (500) */ z-index: 451; /* Above weather widget (300), below search dropdown (500) */
} }
.fab-btn-right { .fab-btn-right {
@ -81,16 +81,50 @@
transform: translateX(-50%); transform: translateX(-50%);
font-size: 10px; font-size: 10px;
font-weight: 700; font-weight: 700;
color: #e2e8f0; color: #1e293b;
text-shadow: 0 1px 4px rgba(0,0,0,0.8); text-shadow: 0 1px 2px rgba(255,255,255,0.8);
white-space: nowrap; white-space: nowrap;
pointer-events: none; pointer-events: none;
background: rgba(255, 255, 255, 0.85);
padding: 2px 6px;
border-radius: 4px;
max-width: 80px;
overflow: hidden;
text-overflow: ellipsis;
} }
.fab-label-time { .fab-label-time {
background: rgba(15, 23, 42, 0.85); background: rgba(15, 23, 42, 0.85);
padding: 2px 6px; color: #e2e8f0;
border-radius: 4px; text-shadow: 0 1px 4px rgba(0,0,0,0.8);
}
.fab-label-cat {
background: rgba(255, 255, 255, 0.9);
color: #1e293b;
}
/* Item labels (category/subcategory names) */
.fab-item-label {
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
margin-top: 4px;
font-size: 9px;
font-weight: 700;
color: #1e293b;
text-shadow: 0 1px 2px rgba(255,255,255,0.9);
white-space: nowrap;
pointer-events: none;
background: rgba(255, 255, 255, 0.9);
padding: 1px 5px;
border-radius: 3px;
}
.fab-sub-label {
font-size: 8px;
margin-top: 3px;
} }
/* Ring containers */ /* Ring containers */
@ -138,6 +172,7 @@
transform: translate(var(--x), var(--y)) scale(1); transform: translate(var(--x), var(--y)) scale(1);
pointer-events: auto; pointer-events: auto;
transition-delay: var(--delay); transition-delay: var(--delay);
z-index: 452; /* Above weather widget when visible */
} }
.fab-item:hover { .fab-item:hover {
@ -175,6 +210,7 @@
animation: fab-pop-in 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) backwards; animation: fab-pop-in 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
animation-delay: var(--delay); animation-delay: var(--delay);
--color: #64748b; --color: #64748b;
z-index: 453; /* Above category items */
} }
.fab-sub.is-active { .fab-sub.is-active {

View File

@ -2,34 +2,34 @@ import React, { useState, useCallback } from "react";
import "./RadialMenu.css"; import "./RadialMenu.css";
const CATEGORIES = [ const CATEGORIES = [
{ id: "News", icon: "fa-solid fa-newspaper", color: "#3b82f6" }, { id: "News", icon: "fa-solid fa-newspaper", color: "#3b82f6", label: "News" },
{ id: "Friends", icon: "fa-solid fa-users", color: "#10b981" }, { id: "Friends", icon: "fa-solid fa-users", color: "#10b981", label: "Social" },
{ id: "Events", icon: "fa-solid fa-calendar", color: "#f59e0b" }, { id: "Events", icon: "fa-solid fa-calendar", color: "#f59e0b", label: "Events" },
{ id: "Market", icon: "fa-solid fa-store", color: "#8b5cf6" }, { id: "Market", icon: "fa-solid fa-store", color: "#8b5cf6", label: "Market" },
]; ];
const SUBCATEGORIES = { const SUBCATEGORIES = {
News: [ News: [
{ id: "World", icon: "fa-solid fa-globe" }, { id: "World", icon: "fa-solid fa-globe", label: "World" },
{ id: "Politics", icon: "fa-solid fa-landmark" }, { id: "Politics", icon: "fa-solid fa-landmark", label: "Politics" },
{ id: "Tech", icon: "fa-solid fa-microchip" }, { id: "Tech", icon: "fa-solid fa-microchip", label: "Tech" },
{ id: "Finance", icon: "fa-solid fa-chart-line" }, { id: "Finance", icon: "fa-solid fa-chart-line", label: "Finance" },
{ id: "Local", icon: "fa-solid fa-location-dot" }, { id: "Local", icon: "fa-solid fa-location-dot", label: "Local" },
], ],
Friends: [ Friends: [
{ id: "Nearby", icon: "fa-solid fa-location-crosshairs" }, { id: "Nearby", icon: "fa-solid fa-location-crosshairs", label: "Near" },
{ id: "Chats", icon: "fa-solid fa-comments" }, { id: "Chats", icon: "fa-solid fa-comments", label: "Chats" },
{ id: "Groups", icon: "fa-solid fa-user-group" }, { id: "Groups", icon: "fa-solid fa-user-group", label: "Groups" },
], ],
Events: [ Events: [
{ id: "Today", icon: "fa-solid fa-calendar-day" }, { id: "Today", icon: "fa-solid fa-calendar-day", label: "Today" },
{ id: "Music", icon: "fa-solid fa-music" }, { id: "Music", icon: "fa-solid fa-music", label: "Music" },
{ id: "Sports", icon: "fa-solid fa-football" }, { id: "Sports", icon: "fa-solid fa-football", label: "Sports" },
], ],
Market: [ Market: [
{ id: "Deals", icon: "fa-solid fa-tags" }, { id: "Deals", icon: "fa-solid fa-tags", label: "Deals" },
{ id: "Tech", icon: "fa-solid fa-laptop" }, { id: "Tech", icon: "fa-solid fa-laptop", label: "Tech" },
{ id: "Auto", icon: "fa-solid fa-car" }, { id: "Auto", icon: "fa-solid fa-car", label: "Auto" },
], ],
}; };
@ -46,6 +46,7 @@ export default function RadialMenu({
onSubcategoryToggle, onSubcategoryToggle,
onTime, onTime,
onWeather, onWeather,
onClearAllFilters,
activeCategories = [], activeCategories = [],
activeSubcategories = [], activeSubcategories = [],
activeTime, activeTime,
@ -59,6 +60,8 @@ export default function RadialMenu({
.filter(c => activeCategories.includes(c.id)) .filter(c => activeCategories.includes(c.id))
.map(c => c.color); .map(c => c.color);
const hasActiveFilters = activeCategories.length > 0 || activeSubcategories.length > 0;
const handleLeftToggle = () => { const handleLeftToggle = () => {
setLeftOpen(!leftOpen); setLeftOpen(!leftOpen);
if (!leftOpen) setRightOpen(false); if (!leftOpen) setRightOpen(false);
@ -85,6 +88,15 @@ export default function RadialMenu({
onWeather?.(); onWeather?.();
}; };
const handleClearAll = () => {
// Clear all category filters
for (const cat of activeCategories) {
onCategoryToggle?.(cat);
}
setLeftOpen(false);
onClearAllFilters?.();
};
// Build gradient for multi-select FAB // Build gradient for multi-select FAB
const fabGradient = activeColors.length === 0 const fabGradient = activeColors.length === 0
? "linear-gradient(135deg, #6366f1 0%, #4f46e5 100%)" ? "linear-gradient(135deg, #6366f1 0%, #4f46e5 100%)"
@ -129,12 +141,13 @@ export default function RadialMenu({
<React.Fragment key={cat.id}> <React.Fragment key={cat.id}>
{/* Category button */} {/* Category button */}
<button <button
className={`fab-item ${leftOpen ? "is-visible" : ""} ${isActive ? "is-active" : ""}`} className={`fab-item fab-cat ${leftOpen ? "is-visible" : ""} ${isActive ? "is-active" : ""}`}
style={{ "--x": `${x}px`, "--y": `${y}px`, "--delay": `${i * 40}ms`, "--color": cat.color }} style={{ "--x": `${x}px`, "--y": `${y}px`, "--delay": `${i * 40}ms`, "--color": cat.color }}
onClick={() => handleCategoryClick(cat.id)} onClick={() => handleCategoryClick(cat.id)}
title={cat.id} title={cat.id}
> >
<i className={cat.icon} /> <i className={cat.icon} />
<span className="fab-item-label">{cat.label}</span>
</button> </button>
{/* Subcategories - appear around the category when active */} {/* Subcategories - appear around the category when active */}
@ -162,6 +175,7 @@ export default function RadialMenu({
title={sub.id} title={sub.id}
> >
<i className={sub.icon} /> <i className={sub.icon} />
<span className="fab-item-label fab-sub-label">{sub.label}</span>
</button> </button>
); );
})} })}
@ -173,10 +187,13 @@ export default function RadialMenu({
{/* Main FAB - split colors */} {/* Main FAB - split colors */}
<button <button
className="fab-btn fab-btn-split" className="fab-btn fab-btn-split"
onClick={handleLeftToggle} onClick={leftOpen && hasActiveFilters ? handleClearAll : handleLeftToggle}
style={{ background: fabGradient }} style={{ background: leftOpen ? "#ef4444" : fabGradient }}
title={leftOpen && hasActiveFilters ? "Clear all filters" : "Categories"}
> >
{activeCategories.length === 0 ? ( {leftOpen ? (
<i className="fa-solid fa-xmark" />
) : activeCategories.length === 0 ? (
<i className="fa-solid fa-layer-group" /> <i className="fa-solid fa-layer-group" />
) : activeCategories.length === 1 ? ( ) : activeCategories.length === 1 ? (
<i className={CATEGORIES.find(c => c.id === activeCategories[0])?.icon || "fa-solid fa-layer-group"} /> <i className={CATEGORIES.find(c => c.id === activeCategories[0])?.icon || "fa-solid fa-layer-group"} />
@ -184,6 +201,7 @@ export default function RadialMenu({
<span className="fab-count">{activeCategories.length}</span> <span className="fab-count">{activeCategories.length}</span>
)} )}
</button> </button>
<span className="fab-label fab-label-cat">{leftOpen ? "Clear" : activeCategories.length > 0 ? activeCategories.join(", ") : "Filter"}</span>
</div> </div>
{/* RIGHT FAB - Time & Weather */} {/* RIGHT FAB - Time & Weather */}