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",
|
"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",
|
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -4062,6 +4062,64 @@ h3 {
|
|||||||
transform: scale(0.9);
|
transform: scale(0.9);
|
||||||
box-shadow: 0 2px 8px rgba(14, 165, 233, 0.3);
|
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 --- */
|
||||||
.bottom-sheet-backdrop {
|
.bottom-sheet-backdrop {
|
||||||
|
|||||||
@ -1794,6 +1794,7 @@ export default function WeeklyView() {
|
|||||||
const [isMobile, setIsMobile] = useState(false);
|
const [isMobile, setIsMobile] = useState(false);
|
||||||
|
|
||||||
const [showMobileFabSheet, setShowMobileFabSheet] = useState(false);
|
const [showMobileFabSheet, setShowMobileFabSheet] = useState(false);
|
||||||
|
const [showMobileFabMenu, setShowMobileFabMenu] = useState(false);
|
||||||
const [fabTaskTitle, setFabTaskTitle] = useState("");
|
const [fabTaskTitle, setFabTaskTitle] = useState("");
|
||||||
|
|
||||||
const fabTextareaRef = useRef<HTMLTextAreaElement>(null);
|
const fabTextareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
@ -8352,15 +8353,43 @@ export default function WeeklyView() {
|
|||||||
isLoading={isFetchingLists}
|
isLoading={isFetchingLists}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Mobile: Floating Action Button for quick task creation */}
|
{/* Mobile: Floating Action Button with quick menu */}
|
||||||
{isMobile && !showMobileFabSheet && !showSettings && !showFocusMode && (
|
{isMobile && !showMobileFabSheet && !showSettings && !showFocusMode && (
|
||||||
<button
|
<>
|
||||||
className="mobile-fab"
|
{showMobileFabMenu && (
|
||||||
onClick={() => setShowMobileFabSheet(true)}
|
<div className="mobile-fab-backdrop" onClick={() => setShowMobileFabMenu(false)} />
|
||||||
title="Add task"
|
)}
|
||||||
>
|
{showMobileFabMenu && (
|
||||||
<Plus size={28} />
|
<div className="mobile-fab-menu">
|
||||||
</button>
|
<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 */}
|
{/* Mobile: Bottom Sheet for task creation */}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user