From d69984c51decff454693a3da4926c29b4c610525 Mon Sep 17 00:00:00 2001
From: gohan5858 <88976739+gohan5858@users.noreply.github.com>
Date: Sun, 27 Oct 2024 01:10:30 +0900
Subject: [PATCH 1/8] =?UTF-8?q?rename:=20=E3=83=91=E3=82=B9=E5=90=8D?=
=?UTF-8?q?=E3=82=92=E3=82=B3=E3=83=B3=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3?=
=?UTF-8?q?=E3=83=88=E5=90=8D=E3=81=AB=E5=90=88=E3=81=86=E3=82=88=E3=81=86?=
=?UTF-8?q?=E3=81=AB=E5=A4=89=E6=9B=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
task_yell/src/app/{enhanced-calendar-todo-app => home}/page.tsx | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename task_yell/src/app/{enhanced-calendar-todo-app => home}/page.tsx (100%)
diff --git a/task_yell/src/app/enhanced-calendar-todo-app/page.tsx b/task_yell/src/app/home/page.tsx
similarity index 100%
rename from task_yell/src/app/enhanced-calendar-todo-app/page.tsx
rename to task_yell/src/app/home/page.tsx
From d083d60c7dc785ed5000a587605aa4e0612a9ce9 Mon Sep 17 00:00:00 2001
From: gohan5858 <88976739+gohan5858@users.noreply.github.com>
Date: Sun, 27 Oct 2024 01:38:02 +0900
Subject: [PATCH 2/8] =?UTF-8?q?chang:=20=E6=9C=80=E6=96=B0=E3=81=AEHome?=
=?UTF-8?q?=E3=83=93=E3=83=A5=E3=83=BC=E3=81=AB=E6=9B=B4=E6=96=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
task_yell/src/app/home/page.tsx | 888 ++++++++++++++++++++++++--------
1 file changed, 661 insertions(+), 227 deletions(-)
diff --git a/task_yell/src/app/home/page.tsx b/task_yell/src/app/home/page.tsx
index a2b2967..a8a273b 100644
--- a/task_yell/src/app/home/page.tsx
+++ b/task_yell/src/app/home/page.tsx
@@ -1,18 +1,21 @@
"use client";
-import { useState, useEffect, useMemo } from "react";
-import { motion, AnimatePresence } from "framer-motion";
import { Button } from "@/components/ui/button";
+import { Calendar } from "@/components/ui/calendar";
import { Checkbox } from "@/components/ui/checkbox";
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
-import { Textarea } from "@/components/ui/textarea";
+import { Label } from "@/components/ui/label";
import {
- Sheet,
- SheetContent,
- SheetHeader,
- SheetTitle,
- SheetTrigger,
-} from "@/components/ui/sheet";
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover";
import {
Select,
SelectContent,
@@ -21,43 +24,42 @@ import {
SelectValue,
} from "@/components/ui/select";
import {
- Menu,
- CalendarIcon,
- ChevronLeft,
- ChevronRight,
- Edit,
- Trash2,
- MapPinIcon,
- UserPlusIcon,
-} from "lucide-react";
+ Sheet,
+ SheetContent,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from "@/components/ui/sheet";
+import { Switch } from "@/components/ui/switch";
+import { Textarea } from "@/components/ui/textarea";
import {
- format,
- startOfMonth,
- endOfMonth,
- eachDayOfInterval,
- isSameMonth,
- isSameDay,
addMonths,
- subMonths,
+ eachDayOfInterval,
+ endOfMonth,
+ format,
getDay,
- isToday,
isFuture,
+ isSameDay,
+ isSameMonth,
+ isToday,
+ startOfMonth,
+ subMonths,
} from "date-fns";
import { ja } from "date-fns/locale";
-import { Calendar } from "@/components/ui/calendar";
+import { AnimatePresence, motion, useDragControls } from "framer-motion";
import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog";
-import { Label } from "@/components/ui/label";
-import { Switch } from "@/components/ui/switch";
+ CalendarIcon,
+ ChevronLeft,
+ ChevronRight,
+ ChevronUp,
+ Edit,
+ MapPinIcon,
+ Menu,
+ Trash2,
+ UserPlusIcon,
+ X,
+} from "lucide-react";
+import { useEffect, useMemo, useRef, useState } from "react";
type Priority = "low" | "medium" | "high";
type Category = "work" | "personal" | "shopping" | "health" | "other";
@@ -226,148 +228,165 @@ function EventCreator({
};
return (
-
-
-
setIsTask(checked as boolean)}
- />
-
+
+
+
+
+ {format(date || new Date(), "yyyy年MM月dd日 (E)", { locale: ja })}
+
+
+ {Array.from({ length: 24 }).map((_, hour) => (
+
+
{`${hour.toString().padStart(2, "0")}:00`}
+
+
+ ))}
+
+
+
+
+ setIsTask(checked as boolean)}
+ />
+
+
-
setTitle(e.target.value)}
- />
+
setTitle(e.target.value)}
+ />
- {!isTask && (
- <>
-
-
-
-
-
-
-
-
-
-
-
+ {!isTask && (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
);
@@ -376,25 +395,27 @@ function EventCreator({
export default function Page() {
const [todos, setTodos] = useState
([]);
const [events, setEvents] = useState([]);
+ const [newTodo, setNewTodo] = useState("");
const [selectedDate, setSelectedDate] = useState(new Date());
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [todoDate, setTodoDate] = useState(selectedDate);
const [selectedDateTodos, setSelectedDateTodos] = useState([]);
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [priority, setPriority] = useState("medium");
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [category, setCategory] = useState("other");
const [currentMonth, setCurrentMonth] = useState(new Date());
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [modalState, setModalState] = useState<
+ "minimized" | "partial" | "full"
+ >("partial");
const [searchTerm, setSearchTerm] = useState("");
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [editingTodo, setEditingTodo] = useState(null);
const [isDarkMode, setIsDarkMode] = useState(false);
const [isEventModalOpen, setIsEventModalOpen] = useState(false);
+ const dragControls = useDragControls();
+ const modalRef = useRef(null);
useEffect(() => {
const filteredTodos = todos.filter((todo) =>
- isSameDay(todo.date, selectedDate),
+ isSameDay(todo.date, selectedDate)
);
setSelectedDateTodos(filteredTodos);
}, [selectedDate, todos]);
@@ -407,14 +428,35 @@ export default function Page() {
}
}, [isDarkMode]);
+ const addTodo = () => {
+ if (newTodo.trim() && todoDate) {
+ const newTodoItem = {
+ id: Date.now(),
+ text: newTodo,
+ completed: false,
+ date: todoDate,
+ priority,
+ category,
+ };
+ setTodos([...todos, newTodoItem]);
+ setNewTodo("");
+ setTodoDate(new Date());
+ setPriority("medium");
+ setCategory("other");
+ if (isSameDay(todoDate, selectedDate)) {
+ setSelectedDateTodos([...selectedDateTodos, newTodoItem]);
+ }
+ }
+ };
+
const toggleTodo = (id: number) => {
const updatedTodos = todos.map((todo) =>
- todo.id === id ? { ...todo, completed: !todo.completed } : todo,
+ todo.id === id ? { ...todo, completed: !todo.completed } : todo
);
setTodos(updatedTodos);
if (selectedDate) {
const updatedSelectedDateTodos = selectedDateTodos.map((todo) =>
- todo.id === id ? { ...todo, completed: !todo.completed } : todo,
+ todo.id === id ? { ...todo, completed: !todo.completed } : todo
);
setSelectedDateTodos(updatedSelectedDateTodos);
}
@@ -424,6 +466,14 @@ export default function Page() {
setEditingTodo(todo);
};
+ const updateTodo = (updatedTodo: Todo) => {
+ const updatedTodos = todos.map((todo) =>
+ todo.id === updatedTodo.id ? updatedTodo : todo
+ );
+ setTodos(updatedTodos);
+ setEditingTodo(null);
+ };
+
const deleteTodo = (id: number) => {
const updatedTodos = todos.filter((todo) => todo.id !== id);
setTodos(updatedTodos);
@@ -455,54 +505,108 @@ export default function Page() {
const baseColor = isDarkMode ? "bg-red-" : "bg-red-";
const intensity = Math.min(count * 100, 900);
const colorClass = `${baseColor}${intensity}`;
- if (count >= 3) {
- return `${colorClass} animate-bounce shadow-lg`;
- }
- return colorClass;
+ return `${colorClass} ${count >= 3 ? "animate-pulse" : ""}`;
};
const renderCalendar = () => {
const days = getDaysInMonth(currentMonth);
const firstDayOfMonth = getDay(days[0]);
+ const weeks = Math.ceil((days.length + firstDayOfMonth) / 7);
return (
-
- {["日", "月", "火", "水", "木", "金", "土"].map((day) => (
-
- {day}
-
- ))}
- {Array(firstDayOfMonth)
- .fill(null)
- .map((_, index) => (
-
+
+
+ {["日", "月", "火", "水", "木", "金", "土"].map((day) => (
+
+ {day}
+
))}
- {days.map((day) => {
- const todoCount = getTodoCountForDay(day);
- const eventCount = getEventCountForDay(day);
- const isSelected = isSameDay(day, selectedDate);
- const isCurrentMonth = isSameMonth(day, currentMonth);
+
+ {Array.from({ length: weeks }).map((_, weekIndex) => {
+ const weekDays = days.slice(
+ weekIndex * 7 - firstDayOfMonth,
+ (weekIndex + 1) * 7 - firstDayOfMonth
+ );
+ const maxEventsInWeek = Math.max(
+ ...weekDays.map((day) =>
+ day ? getTodoCountForDay(day) + getEventCountForDay(day) : 0
+ )
+ );
+ const weekHeight =
+ maxEventsInWeek > 2 ? Math.min(maxEventsInWeek * 20, 100) : "auto";
return (
-
handleDateSelect(day)}
- whileHover={{ scale: 1.1 }}
- whileTap={{ scale: 0.95 }}
+
-
{format(day, "d")}
- {(todoCount > 0 || eventCount > 0) && (
-
- {todoCount + eventCount}
-
- )}
-
+ {Array(7)
+ .fill(null)
+ .map((_, dayIndex) => {
+ const day = weekDays[dayIndex];
+ if (!day)
+ return (
+
+ );
+
+ const todoCount = getTodoCountForDay(day);
+ const eventCount = getEventCountForDay(day);
+ const isSelected = isSameDay(day, selectedDate);
+ const isCurrentMonth = isSameMonth(day, currentMonth);
+ const dayItems = [
+ ...todos.filter((todo) => isSameDay(todo.date, day)),
+ ...events.filter((event) => isSameDay(event.start, day)),
+ ];
+
+ return (
+
handleDateSelect(day)}
+ whileHover={{ scale: 1.05 }}
+ whileTap={{ scale: 0.95 }}
+ >
+
+ {format(day, "d")}
+
+ {(todoCount > 0 || eventCount > 0) && (
+
+ {dayItems.slice(0, 2).map((item, index) => (
+
+ {"text" in item ? item.text : item.title}
+
+ ))}
+ {dayItems.length > 2 && (
+
+ +{dayItems.length - 2} more
+
+ )}
+
+ )}
+
+ );
+ })}
+
);
})}
@@ -521,7 +625,11 @@ export default function Page() {
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
- className={`flex items-center p-2 rounded ${todo.completed ? "bg-gray-200 dark:bg-gray-700" : priorityColors[todo.priority]} transition-colors duration-200`}
+ className={`flex items-center p-2 rounded ${
+ todo.completed
+ ? "bg-gray-200 dark:bg-gray-700"
+ : priorityColors[todo.priority]
+ } transition-colors duration-200`}
>
);
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
const filteredTodos = useMemo(() => {
return todos.filter(
(todo) =>
todo.text.toLowerCase().includes(searchTerm.toLowerCase()) ||
- format(todo.date, "yyyy/MM/dd").includes(searchTerm),
+ format(todo.date, "yyyy/MM/dd").includes(searchTerm)
);
}, [todos, searchTerm]);
@@ -591,13 +698,22 @@ export default function Page() {
(event) =>
event.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
event.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
- format(event.start, "yyyy/MM/dd").includes(searchTerm),
+ format(event.start, "yyyy/MM/dd").includes(searchTerm)
);
}, [events, searchTerm]);
+ const sortedTodos = useMemo(() => {
+ return [...filteredTodos].sort((a, b) => {
+ if (a.completed === b.completed) {
+ return b.date.getTime() - a.date.getTime();
+ }
+ return a.completed ? 1 : -1;
+ });
+ }, [filteredTodos]);
+
const sortedEvents = useMemo(() => {
return [...filteredEvents].sort(
- (a, b) => b.start.getTime() - a.start.getTime(),
+ (a, b) => b.start.getTime() - a.start.getTime()
);
}, [filteredEvents]);
@@ -606,11 +722,18 @@ export default function Page() {
.sort((a, b) => a.date.getTime() - b.date.getTime())
.slice(0, 5);
+ const handleStatusBarClick = () => {
+ setModalState((prevState) => {
+ if (prevState === "minimized") return "partial";
+ if (prevState === "partial") return "full";
+ return "partial";
+ });
+ };
+
return (
- {/* ハンバーガーメニューとその中身 */}
-
+
+
+
+
setTitle(e.target.value)}
+ />
+
-
setTitle(e.target.value)}
- />
-
- {!isTask && (
- <>
-
-
-
-
-
- {date
- ? format(date, "yyyy年MM月dd日 (E)", { locale: ja })
- : "日付を選択"}
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-