diff --git a/package.json b/package.json
index 501f0cc..1036662 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "my-weekly-todo-list",
- "version": "1.6.0",
+ "version": "1.7.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": {
@@ -58,4 +58,4 @@
"ts-jest": "^29.0.0",
"typescript": "^5.0.0"
}
-}
+}
\ No newline at end of file
diff --git a/scripts/boot-update.sh b/scripts/boot-update.sh
new file mode 100755
index 0000000..3d21c6a
--- /dev/null
+++ b/scripts/boot-update.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Boot Update Script: Automatically pull latest main, build, and prepare for PM2
+# This script runs on LXC container boot BEFORE PM2 starts.
+# It ensures the app is always up-to-date with the main branch.
+
+set -e
+
+APP_DIR="/root/My-Weekly-ToDo-List"
+LOG_FILE="/var/log/app-boot-update.log"
+
+log() {
+ echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
+}
+
+log "=== Boot update started ==="
+
+cd "$APP_DIR"
+
+# Check if there are remote changes
+log "Fetching from origin..."
+git fetch origin main 2>&1 | tee -a "$LOG_FILE"
+
+LOCAL=$(git rev-parse HEAD)
+REMOTE=$(git rev-parse origin/main)
+
+if [ "$LOCAL" = "$REMOTE" ]; then
+ log "Already up-to-date. No rebuild needed."
+ log "=== Boot update finished (no changes) ==="
+ exit 0
+fi
+
+log "Changes detected. Updating from $LOCAL to $REMOTE"
+
+log "Pulling latest changes..."
+git checkout main 2>&1 | tee -a "$LOG_FILE"
+git pull origin main 2>&1 | tee -a "$LOG_FILE"
+
+log "Installing dependencies..."
+npm install 2>&1 | tee -a "$LOG_FILE"
+
+log "Updating database schema..."
+npx prisma db push 2>&1 | tee -a "$LOG_FILE"
+
+log "Regenerating Prisma client..."
+npx prisma generate 2>&1 | tee -a "$LOG_FILE"
+
+log "Building application..."
+npm run build 2>&1 | tee -a "$LOG_FILE"
+
+log "=== Boot update finished (rebuilt successfully) ==="
diff --git a/src/app/auth/verify-email/page.tsx b/src/app/auth/verify-email/page.tsx
index dc26efb..38d17d8 100644
--- a/src/app/auth/verify-email/page.tsx
+++ b/src/app/auth/verify-email/page.tsx
@@ -1,10 +1,10 @@
'use client';
-import React, { useState, useRef, useEffect } from 'react';
+import React, { useState, useRef, useEffect, Suspense } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import Link from 'next/link';
-export default function VerifyEmailPage() {
+function VerifyEmailContent() {
const router = useRouter();
const searchParams = useSearchParams();
const email = searchParams.get('email') || '';
@@ -262,4 +262,19 @@ export default function VerifyEmailPage() {
);
+}
+
+export default function VerifyEmailPage() {
+ return (
+
+
+
My Weekly ToDo's
+
Loading...
+
+
+ }>
+
+
+ );
}
\ No newline at end of file
diff --git a/src/app/globals.css b/src/app/globals.css
index 61d374f..0299435 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1757,18 +1757,137 @@ h3 {
background-color: transparent;
}
-/* Responsive */
+/* ============================================
+ RESPONSIVE BREAKPOINTS
+ ============================================ */
+
+/* === Tablet (≤ 1024px): 5-day view === */
+@media (max-width: 1024px) {
+ .weekly-days-grid {
+ grid-template-columns: repeat(5, 1fr) !important;
+ }
+
+ .all-day-events-grid {
+ grid-template-columns: repeat(5, 1fr) !important;
+ }
+
+ .weekly-someday-lists-grid {
+ grid-template-columns: repeat(5, 1fr) !important;
+ }
+}
+
+/* === Phone landscape / small tablet (≤ 768px): 3-day view === */
@media (max-width: 768px) {
.weekly-days-grid {
- grid-template-columns: 1fr !important;
+ grid-template-columns: repeat(3, 1fr) !important;
+ }
+
+ .all-day-events-grid {
+ grid-template-columns: repeat(3, 1fr) !important;
+ }
+
+ .weekly-someday-lists-grid {
+ grid-template-columns: repeat(3, 1fr) !important;
}
.weekly-someday-lists {
grid-template-columns: 1fr;
}
+ /* Compact time column */
.time-column {
- display: none;
+ width: 40px;
+ }
+
+ .time-slot-label {
+ font-size: 0.55rem;
+ padding: 0 0.25rem;
+ }
+
+ /* Compact day headers */
+ .weekly-day-header {
+ padding: 0.5rem 0.25rem;
+ }
+
+ .weekly-day-name {
+ font-size: 0.8rem;
+ }
+
+ .weekly-day-date {
+ font-size: 0.7rem;
+ }
+
+ /* Smaller text in time slots */
+ .time-slot-task {
+ font-size: 0.7rem;
+ }
+
+ .time-slot-event .event-title {
+ font-size: 0.75rem;
+ }
+
+ .time-slot-event .event-time-row {
+ font-size: 0.65rem;
+ }
+
+ /* Touch-friendly: taller minimum slot height */
+ .time-slot {
+ min-height: 28px;
+ }
+}
+
+/* === Phone portrait (≤ 480px): 1-day view === */
+@media (max-width: 480px) {
+ .weekly-days-grid {
+ grid-template-columns: 1fr !important;
+ }
+
+ .all-day-events-grid {
+ grid-template-columns: 1fr !important;
+ }
+
+ .weekly-someday-lists-grid {
+ grid-template-columns: 1fr !important;
+ }
+
+ /* Narrower time column on phone */
+ .time-column {
+ width: 36px;
+ }
+
+ .time-slot-label {
+ font-size: 0.5rem;
+ padding: 0 2px;
+ }
+
+ /* Full-width header on phone */
+ .weekly-header {
+ padding: 0.5rem 0.75rem;
+ }
+
+ .weekly-day-header {
+ padding: 0.5rem;
+ }
+
+ /* Larger tap targets */
+ .time-slot {
+ min-height: 32px;
+ padding: 0px 4px;
+ }
+
+ .time-slot-task {
+ font-size: 0.75rem;
+ padding: 3px 0;
+ }
+
+ /* Settings panel full-width on phone */
+ .weekly-settings-sidebar {
+ width: 100% !important;
+ max-width: 100vw;
+ }
+
+ .preferences-panel {
+ width: 100%;
}
}
@@ -3119,55 +3238,59 @@ h3 {
display: none; /* Chrome, Safari, Opera */
}
-/* Responsive Design */
+/* Responsive Design - Header & Layout */
@media (max-width: 768px) {
- /* Mobile/Tablet adjustment */
+ /* Mobile header: stack and compact */
.weekly-header {
- flex-direction: column;
+ flex-direction: row;
+ flex-wrap: wrap;
height: auto;
- padding: 10px;
- gap: 10px;
+ padding: 0.5rem 0.75rem;
+ gap: 6px;
}
-
+
.weekly-header > div {
- width: 100%;
- justify-content: center;
+ flex-shrink: 0;
}
-
+
/* Fix overlap on mobile by removing absolute positioning */
.weekly-header .absolute {
position: static !important;
transform: none !important;
left: auto !important;
- margin: 5px 0;
- }
-
- .weekly-btn-icon {
- width: 36px;
- height: 36px;
+ margin: 0;
}
- /* Stack days vertically on mobile */
+ .weekly-btn-icon {
+ width: 32px;
+ height: 32px;
+ }
+
+ /* Stack days vertically in list view on mobile */
.list-view .weekly-days-grid {
grid-template-columns: 1fr !important;
overflow-y: auto;
}
- .time-grid-wrapper {
- flex-direction: column;
- height: calc(100vh - 120px); /* Adjust for header */
- }
-
.weekly-day-column {
min-height: auto;
- border-right: none !important;
- border-bottom: 1px solid #ccc;
}
-
- /* Ensure sidebar is scrollable and accessible */
- .weekly-settings-sidebar {
- width: 100%;
- max-width: 100vw;
+}
+
+@media (max-width: 480px) {
+ /* Phone: make header even more compact */
+ .weekly-header {
+ padding: 0.4rem 0.5rem;
+ gap: 4px;
+ }
+
+ .weekly-btn-icon {
+ width: 28px;
+ height: 28px;
+ }
+
+ .weekly-logo {
+ font-size: 1rem;
}
}
diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx
index 5a4e8cf..b3328af 100644
--- a/src/components/WeeklyView.tsx
+++ b/src/components/WeeklyView.tsx
@@ -488,7 +488,29 @@ export default function WeeklyView() {
return d;
});
const [viewDays, setViewDays] = useState(7);
+ const savedViewDaysRef = useRef(7); // Track user's saved preference for restoring on resize
const [isLoading, setIsLoading] = useState(true);
+
+ // Responsive: auto-adjust viewDays based on screen width
+ useEffect(() => {
+ const getResponsiveViewDays = (width: number): number => {
+ if (width <= 480) return 1;
+ if (width <= 768) return 3;
+ if (width <= 1024) return Math.min(savedViewDaysRef.current, 5);
+ return savedViewDaysRef.current;
+ };
+
+ const handleResize = () => {
+ const responsiveDays = getResponsiveViewDays(window.innerWidth);
+ setViewDays(responsiveDays);
+ };
+
+ // Set initial value
+ handleResize();
+
+ window.addEventListener('resize', handleResize);
+ return () => window.removeEventListener('resize', handleResize);
+ }, []); // savedViewDaysRef is a ref, so no dependency needed
const [isSyncing, setIsSyncing] = useState(false);
const [syncError, setSyncError] = useState(null);
const syncCountRef = useRef(0);
@@ -1361,7 +1383,10 @@ export default function WeeklyView() {
setViewStyle(data.user.viewStyle as ViewStyle);
setShowTimeGrid(data.user.showTimeGrid ?? true);
}
- if (data.user.viewDays !== undefined) setViewDays(data.user.viewDays);
+ if (data.user.viewDays !== undefined) {
+ setViewDays(data.user.viewDays);
+ savedViewDaysRef.current = data.user.viewDays;
+ }
if (data.user.cellDuration !== undefined)
setCellDuration(data.user.cellDuration as CellDuration);
setShowNextTask(data.user.showNextTask || false);
@@ -3481,6 +3506,7 @@ export default function WeeklyView() {
key={num}
onClick={() => {
setViewDays(num);
+ savedViewDaysRef.current = num;
saveSetting("viewDays", num);
}}
className={`px-2 py-0.5 text-xs rounded transition-colors ${viewDays === num ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
@@ -9851,7 +9877,7 @@ function SettingsSidebar({
color: "var(--weekly-settings-label)",
}}
>
- Version {process.env.NEXT_PUBLIC_APP_VERSION || "1.0.0"}
+ Version {process.env.NEXT_PUBLIC_APP_VERSION || "1.7.0"}