feat: transform mobile FAB into quick action menu
FAB now opens a fan menu with 4 options instead of directly adding tasks: - Task: opens the existing bottom sheet for quick task entry - Event: opens the calendar event modal - Focus: enters focus mode - Search: opens search modal FAB rotates to X when menu is open, backdrop dismisses on tap. Each menu item has a colored icon bubble with label. v1.41.0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2d386362ca
commit
18da568b9f
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "my-weekly-todo-list",
|
||||
"version": "1.40.1",
|
||||
"version": "1.41.0",
|
||||
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@ -4062,6 +4062,64 @@ h3 {
|
||||
transform: scale(0.9);
|
||||
box-shadow: 0 2px 8px rgba(14, 165, 233, 0.3);
|
||||
}
|
||||
.mobile-fab.active {
|
||||
background: #ef4444;
|
||||
box-shadow: 0 4px 14px rgba(239, 68, 68, 0.4);
|
||||
}
|
||||
|
||||
/* --- FAB Quick Menu --- */
|
||||
.mobile-fab-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
z-index: 899;
|
||||
animation: fadeIn 0.15s ease;
|
||||
}
|
||||
.mobile-fab-menu {
|
||||
position: fixed;
|
||||
bottom: calc(92px + env(safe-area-inset-bottom, 0px));
|
||||
right: 24px;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
gap: 12px;
|
||||
z-index: 901;
|
||||
animation: fabMenuIn 0.2s ease-out;
|
||||
}
|
||||
@keyframes fabMenuIn {
|
||||
from { opacity: 0; transform: translateY(10px) scale(0.95); }
|
||||
to { opacity: 1; transform: translateY(0) scale(1); }
|
||||
}
|
||||
.mobile-fab-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-direction: row-reverse;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.mobile-fab-menu-item span {
|
||||
background: var(--weekly-bg, #fff);
|
||||
color: var(--weekly-text, #333);
|
||||
padding: 6px 14px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.mobile-fab-menu-icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* --- Bottom Sheet --- */
|
||||
.bottom-sheet-backdrop {
|
||||
|
||||
@ -1794,6 +1794,7 @@ export default function WeeklyView() {
|
||||
const [isMobile, setIsMobile] = useState(false);
|
||||
|
||||
const [showMobileFabSheet, setShowMobileFabSheet] = useState(false);
|
||||
const [showMobileFabMenu, setShowMobileFabMenu] = useState(false);
|
||||
const [fabTaskTitle, setFabTaskTitle] = useState("");
|
||||
|
||||
const fabTextareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
@ -8352,15 +8353,43 @@ export default function WeeklyView() {
|
||||
isLoading={isFetchingLists}
|
||||
/>
|
||||
|
||||
{/* Mobile: Floating Action Button for quick task creation */}
|
||||
{/* Mobile: Floating Action Button with quick menu */}
|
||||
{isMobile && !showMobileFabSheet && !showSettings && !showFocusMode && (
|
||||
<button
|
||||
className="mobile-fab"
|
||||
onClick={() => setShowMobileFabSheet(true)}
|
||||
title="Add task"
|
||||
>
|
||||
<Plus size={28} />
|
||||
</button>
|
||||
<>
|
||||
{showMobileFabMenu && (
|
||||
<div className="mobile-fab-backdrop" onClick={() => setShowMobileFabMenu(false)} />
|
||||
)}
|
||||
{showMobileFabMenu && (
|
||||
<div className="mobile-fab-menu">
|
||||
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowMobileFabSheet(true); }}>
|
||||
<div className="mobile-fab-menu-icon" style={{ background: "#0ea5e9" }}><Plus size={18} /></div>
|
||||
<span>{language === "de" ? "Aufgabe" : "Task"}</span>
|
||||
</button>
|
||||
<button className="mobile-fab-menu-item" onClick={() => {
|
||||
setShowMobileFabMenu(false);
|
||||
const now = new Date();
|
||||
setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` });
|
||||
}}>
|
||||
<div className="mobile-fab-menu-icon" style={{ background: "#8b5cf6" }}><Calendar size={18} /></div>
|
||||
<span>{language === "de" ? "Termin" : "Event"}</span>
|
||||
</button>
|
||||
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowFocusMode(true); }}>
|
||||
<div className="mobile-fab-menu-icon" style={{ background: "#f59e0b" }}><Zap size={18} /></div>
|
||||
<span>{language === "de" ? "Fokus" : "Focus"}</span>
|
||||
</button>
|
||||
<button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setIsSearchOpen(true); }}>
|
||||
<div className="mobile-fab-menu-icon" style={{ background: "#10b981" }}><Search size={18} /></div>
|
||||
<span>{language === "de" ? "Suche" : "Search"}</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
className={`mobile-fab ${showMobileFabMenu ? "active" : ""}`}
|
||||
onClick={() => setShowMobileFabMenu(!showMobileFabMenu)}
|
||||
>
|
||||
<Plus size={28} style={{ transform: showMobileFabMenu ? "rotate(45deg)" : "rotate(0deg)", transition: "transform 0.2s ease" }} />
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Mobile: Bottom Sheet for task creation */}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user