diff --git a/package.json b/package.json index d819ed8..b4fcebf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-weekly-todo-list", - "version": "1.45.0", + "version": "1.46.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": { diff --git a/src/app/globals.css b/src/app/globals.css index 792b996..e84caf8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3879,10 +3879,14 @@ h3 { .weekly-day-header { position: sticky; top: calc(48px + env(safe-area-inset-top, 0px)); - z-index: 10; + z-index: 40; background: var(--weekly-bg, white); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); } + /* In time-grid mode, the scroll container is time-grid-wrapper, so top=0 */ + .time-grid-on .weekly-day-header { + top: 0 !important; + } } @media (max-width: 480px) { @@ -4308,7 +4312,7 @@ h3 { @media (max-width: 768px) { .time-grid-on .weekly-days-grid { overflow-y: auto !important; - overflow-x: hidden !important; + overflow-x: clip !important; } .time-grid-on .weekly-day-column { overflow-y: visible !important; @@ -4358,8 +4362,12 @@ h3 { } @media (max-width: 768px) { + /* Sticky day header: top: 0 relative to the scroll container (time-grid-wrapper) */ .time-grid-on .weekly-day-header { - top: calc(48px + env(safe-area-inset-top, 0px)) !important; + position: sticky !important; + top: 0 !important; + z-index: 40 !important; + background-color: var(--weekly-bg, white); } /* On mobile, time-column-header should NOT be sticky โ it wastes vertical space */ .time-grid-on .time-column-header { diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index ad244a0..272e1cd 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -14,7 +14,17 @@ import TaskRecurrenceModal from "./RecurrenceModal"; import { GridTaskBlock } from "./GridTaskBlock"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faApple, faGoogle, faMicrosoft } from "@fortawesome/free-brands-svg-icons"; -import { faServer } from "@fortawesome/free-solid-svg-icons"; +import { + faServer, faFolder, faBriefcase, faBullseye, faRocket, faStar, + faLightbulb, faFire, faPalette, faMusic, faMobileScreen, faLaptop, + faGlobe, faHouse, faBuilding, faChartBar, faChartLine, faWrench, + faBolt, faGamepad, faPen, faBook, faGraduationCap, faFlask, + faMicroscope, faDumbbell, faUtensils, faPlane, faLeaf, faHeart, + faCartShopping, faCoins, faGift, faCamera, faFilm, faBroom, + faPaw, faEarthAmericas, faLock, faCheck, faCode, faCube, + faUsers, faCar, faMountain, faUmbrella, faClock, faTag, + IconDefinition, +} from "@fortawesome/free-solid-svg-icons"; import FocusModeOverlay from "./FocusModeOverlay"; import { @@ -5762,9 +5772,9 @@ export default function WeeklyView() { {/* Mobile Header */} {isMobile && ( - {/* Left: Menu button */} - setShowSettings(true)} title="Menu" style={{ color: darkMode ? "#e5e7eb" : "#6b7280" }}> - + {/* Left: Quick settings */} + setShowQuickSettings(true)} title="Quick Settings" style={{ color: darkMode ? "#e5e7eb" : "#6b7280" }}> + {/* Center: Date display (tap to jump to date) */} @@ -5802,9 +5812,9 @@ export default function WeeklyView() { - {/* Right: Search */} - setIsSearchOpen(true)} title="Search" style={{ color: darkMode ? "#e5e7eb" : "#6b7280" }}> - + {/* Right: Settings menu */} + setShowSettings(true)} title="Settings" style={{ color: darkMode ? "#e5e7eb" : "#6b7280" }}> + )} @@ -6345,7 +6355,7 @@ export default function WeeklyView() { > {t.filterByProject} {projects.map(p => ( - {p.icon || "๐"} {p.name} + โ {p.name} ))} + {icon} - {w.temp}ยฐ + {w.temp}ยฐ ); })()} @@ -9274,7 +9284,7 @@ function TaskItem({ setShowProjectPicker(false); }} > - {p.icon || "๐"} + {p.name} @@ -9500,13 +9510,43 @@ function TaskItem({ } // Projects Sidebar Component -const projectEmojisGlobal = [ - "๐", "๐", "๐ผ", "๐ฏ", "๐", "โญ", "๐ก", "๐ฅ", "๐จ", "๐ต", - "๐ฑ", "๐ป", "๐", "๐ ", "๐ข", "๐", "๐", "๐ง", "โก", "๐ฎ", - "๐", "๐", "๐", "๐งช", "๐ฌ", "๐๏ธ", "๐ฝ๏ธ", "โ๏ธ", "๐ฟ", "โค๏ธ", - "๐", "๐ฐ", "๐", "๐ธ", "๐ฌ", "๐งน", "๐พ", "๐", "๐", "โ ", +const projectIconsGlobal: { name: string; icon: IconDefinition }[] = [ + { name: "folder", icon: faFolder }, { name: "briefcase", icon: faBriefcase }, + { name: "bullseye", icon: faBullseye }, { name: "rocket", icon: faRocket }, + { name: "star", icon: faStar }, { name: "lightbulb", icon: faLightbulb }, + { name: "fire", icon: faFire }, { name: "palette", icon: faPalette }, + { name: "music", icon: faMusic }, { name: "mobile", icon: faMobileScreen }, + { name: "laptop", icon: faLaptop }, { name: "globe", icon: faGlobe }, + { name: "house", icon: faHouse }, { name: "building", icon: faBuilding }, + { name: "chart-bar", icon: faChartBar }, { name: "chart-line", icon: faChartLine }, + { name: "wrench", icon: faWrench }, { name: "bolt", icon: faBolt }, + { name: "gamepad", icon: faGamepad }, { name: "pen", icon: faPen }, + { name: "book", icon: faBook }, { name: "graduation-cap", icon: faGraduationCap }, + { name: "flask", icon: faFlask }, { name: "microscope", icon: faMicroscope }, + { name: "dumbbell", icon: faDumbbell }, { name: "utensils", icon: faUtensils }, + { name: "plane", icon: faPlane }, { name: "leaf", icon: faLeaf }, + { name: "heart", icon: faHeart }, { name: "cart-shopping", icon: faCartShopping }, + { name: "coins", icon: faCoins }, { name: "gift", icon: faGift }, + { name: "camera", icon: faCamera }, { name: "film", icon: faFilm }, + { name: "broom", icon: faBroom }, { name: "paw", icon: faPaw }, + { name: "earth", icon: faEarthAmericas }, { name: "lock", icon: faLock }, + { name: "check", icon: faCheck }, { name: "code", icon: faCode }, + { name: "cube", icon: faCube }, { name: "users", icon: faUsers }, + { name: "car", icon: faCar }, { name: "mountain", icon: faMountain }, + { name: "umbrella", icon: faUmbrella }, { name: "clock", icon: faClock }, + { name: "tag", icon: faTag }, ]; +// Helper to render a project icon (FA name or legacy emoji) +function ProjectIcon({ icon, size = 18, color }: { icon?: string | null; size?: number; color?: string }) { + if (!icon) return ; + // Check if it's an FA icon name + const found = projectIconsGlobal.find((i) => i.name === icon); + if (found) return ; + // Legacy emoji fallback + return {icon}; +} + function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onClose }: { darkMode: boolean; language: string; @@ -9516,12 +9556,12 @@ function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onCl }) { const [newProjectName, setNewProjectName] = useState(""); const [newProjectColor, setNewProjectColor] = useState("#3b82f6"); - const [newProjectIcon, setNewProjectIcon] = useState("๐"); + const [newProjectIcon, setNewProjectIcon] = useState("folder"); const [showNewIconPicker, setShowNewIconPicker] = useState(false); const [editingId, setEditingId] = useState(null); const [editName, setEditName] = useState(""); const [editColor, setEditColor] = useState(""); - const [editIcon, setEditIcon] = useState(""); + const [editIcon, setEditIcon] = useState("folder"); const [showEditIconPicker, setShowEditIconPicker] = useState(false); const t = { @@ -9539,7 +9579,7 @@ function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onCl const createProject = () => { if (!newProjectName.trim()) return; fetch("/api/projects", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: newProjectName.trim(), color: newProjectColor, icon: newProjectIcon }) }) - .then(() => { onProjectsChanged(); setNewProjectName(""); setNewProjectIcon("๐"); }); + .then(() => { onProjectsChanged(); setNewProjectName(""); setNewProjectIcon("folder"); }); }; const updateProject = (id: string) => { @@ -9579,7 +9619,7 @@ function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onCl {projects.length === 0 ? ( - ๐ + {t.noProjects} ) : ( @@ -9589,15 +9629,15 @@ function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onCl - setShowEditIconPicker(!showEditIconPicker)} style={{ width: "40px", height: "40px", borderRadius: "10px", border: `1px solid ${darkMode ? "#555" : "#e5e7eb"}`, background: darkMode ? "#1e1e2e" : "#fff", cursor: "pointer", fontSize: "20px", display: "flex", alignItems: "center", justifyContent: "center" }}> - {editIcon || "๐"} + setShowEditIconPicker(!showEditIconPicker)} style={{ width: "40px", height: "40px", borderRadius: "10px", border: `1px solid ${darkMode ? "#555" : "#e5e7eb"}`, background: darkMode ? "#1e1e2e" : "#fff", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}> + {showEditIconPicker && ( - + - {projectEmojisGlobal.map((emoji) => ( - { setEditIcon(emoji); setShowEditIconPicker(false); }} style={{ width: "28px", height: "28px", border: "none", background: editIcon === emoji ? (darkMode ? "#374151" : "#f3f4f6") : "transparent", borderRadius: "6px", cursor: "pointer", fontSize: "16px", display: "flex", alignItems: "center", justifyContent: "center" }}> - {emoji} + {projectIconsGlobal.map((item) => ( + { setEditIcon(item.name); setShowEditIconPicker(false); }} style={{ width: "30px", height: "30px", border: "none", background: editIcon === item.name ? (darkMode ? "#374151" : "#e0e7ff") : "transparent", borderRadius: "6px", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", color: darkMode ? "#d1d5db" : "#555" }}> + ))} @@ -9616,11 +9656,11 @@ function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onCl ) : ( <> - {p.icon || "๐"} + {p.name} - { setEditingId(p.id); setEditName(p.name); setEditColor(p.color || "#999"); setEditIcon(p.icon || "๐"); setShowEditIconPicker(false); }} style={{ padding: "6px", opacity: 0.5, cursor: "pointer", background: "none", border: "none", borderRadius: "6px", color: darkMode ? "#ccc" : "#333" }} title="Edit"> + { setEditingId(p.id); setEditName(p.name); setEditColor(p.color || "#999"); setEditIcon(p.icon || "folder"); setShowEditIconPicker(false); }} style={{ padding: "6px", opacity: 0.5, cursor: "pointer", background: "none", border: "none", borderRadius: "6px", color: darkMode ? "#ccc" : "#333" }} title="Edit"> deleteProject(p.id, p.name)} style={{ padding: "6px", opacity: 0.5, cursor: "pointer", color: "#ef4444", background: "none", border: "none", borderRadius: "6px" }} title="Delete"> @@ -9638,15 +9678,15 @@ function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onCl {t.addProject} - setShowNewIconPicker(!showNewIconPicker)} style={{ width: "40px", height: "40px", borderRadius: "10px", border: `1px solid ${darkMode ? "#555" : "#e5e7eb"}`, background: darkMode ? "#2a2a3a" : "#fff", cursor: "pointer", fontSize: "20px", display: "flex", alignItems: "center", justifyContent: "center" }}> - {newProjectIcon} + setShowNewIconPicker(!showNewIconPicker)} style={{ width: "40px", height: "40px", borderRadius: "10px", border: `1px solid ${darkMode ? "#555" : "#e5e7eb"}`, background: darkMode ? "#2a2a3a" : "#fff", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}> + {showNewIconPicker && ( - + - {projectEmojisGlobal.map((emoji) => ( - { setNewProjectIcon(emoji); setShowNewIconPicker(false); }} style={{ width: "28px", height: "28px", border: "none", background: newProjectIcon === emoji ? (darkMode ? "#374151" : "#f3f4f6") : "transparent", borderRadius: "6px", cursor: "pointer", fontSize: "16px", display: "flex", alignItems: "center", justifyContent: "center" }}> - {emoji} + {projectIconsGlobal.map((item) => ( + { setNewProjectIcon(item.name); setShowNewIconPicker(false); }} style={{ width: "30px", height: "30px", border: "none", background: newProjectIcon === item.name ? (darkMode ? "#374151" : "#e0e7ff") : "transparent", borderRadius: "6px", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", color: darkMode ? "#d1d5db" : "#555" }}> + ))} @@ -10128,13 +10168,6 @@ function SettingsSidebar({ const [showEditProjectIconPicker, setShowEditProjectIconPicker] = useState(false); const [weatherSearchResults, setWeatherSearchResults] = useState([]); - const projectEmojis = [ - "๐", "๐", "๐ผ", "๐ฏ", "๐", "โญ", "๐ก", "๐ฅ", "๐จ", "๐ต", - "๐ฑ", "๐ป", "๐", "๐ ", "๐ข", "๐", "๐", "๐ง", "โก", "๐ฎ", - "๐", "๐", "๐", "๐งช", "๐ฌ", "๐๏ธ", "๐ฝ๏ธ", "โ๏ธ", "๐ฟ", "โค๏ธ", - "๐", "๐ฐ", "๐", "๐ธ", "๐ฌ", "๐งน", "๐พ", "๐", "๐", "โ ", - ]; - // Fetch lists when the calendar tab is selected useEffect(() => { if (activeTab === "calendar") {
{t.noProjects}
{t.addProject}