mirror of
https://github.com/nagaoo0/HabbitGrid.git
synced 2026-04-19 15:23:16 +00:00
Compare commits
2 Commits
1.0.0
...
bb64bacd1e
| Author | SHA1 | Date | |
|---|---|---|---|
| bb64bacd1e | |||
| 7b513bca28 |
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { getColorIntensity, isToday, formatDate, getWeekdayLabel } from '../lib/utils-habit';
|
||||
import { toggleCompletion } from '../lib/storage';
|
||||
@@ -29,29 +29,37 @@ const HabitGrid = ({ habit, onUpdate, fullView = false }) => {
|
||||
return weeksArray;
|
||||
}, [fullView]);
|
||||
|
||||
useEffect(() => {
|
||||
// Scroll to the rightmost (most recent) week on mount
|
||||
const gridScroll = document.querySelector('.grid-scroll');
|
||||
if (gridScroll) {
|
||||
gridScroll.scrollLeft = gridScroll.scrollWidth;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleCellClick = (date) => {
|
||||
toggleCompletion(habit.id, formatDate(date));
|
||||
onUpdate();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-slate-800 rounded-2xl p-6 shadow-sm border border-slate-200 dark:border-slate-700">
|
||||
<div className="mb-4">
|
||||
<div className="bg-white dark:bg-slate-800 rounded-2xl p-4 pt-0 shadow-sm border border-slate-200 dark:border-slate-700">
|
||||
<div className="mb-2">
|
||||
<h2 className="text-lg font-semibold mb-1">Activity Calendar</h2>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Tap any day to mark it as complete
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto grid-scroll">
|
||||
<div className="inline-flex gap-1">
|
||||
<div className="overflow-x-auto grid-scroll mt-2">
|
||||
<div className="inline-flex gap-1 mb-4">
|
||||
{/* Weekday labels: Monday (top) to Sunday (bottom) */}
|
||||
<div className="flex flex-col gap-1 mr-2">
|
||||
<div className="h-3" />
|
||||
<div className="h-1" />
|
||||
{[1, 2, 3, 4, 5, 6, 0].map((day) => (
|
||||
<div
|
||||
key={day}
|
||||
className="h-3 flex items-center justify-end text-xs text-muted-foreground pr-1"
|
||||
className="h-3 flex items-center justify-end text-xs text-muted-foreground pr-0"
|
||||
>
|
||||
{getWeekdayLabel(day)}
|
||||
</div>
|
||||
|
||||
@@ -7,8 +7,15 @@ const MiniGrid = ({ habit, onUpdate }) => {
|
||||
const today = new Date();
|
||||
// Show fewer days on mobile for better aspect ratio
|
||||
const isMobile = window.innerWidth < 640; // Tailwind 'sm' breakpoint
|
||||
const numDays = isMobile ? 14 : 28;
|
||||
const numDays = isMobile ? 11 : 28;
|
||||
const days = [];
|
||||
const scrollRef = React.useRef(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (scrollRef.current) {
|
||||
scrollRef.current.scrollLeft = scrollRef.current.scrollWidth;
|
||||
}
|
||||
}, [numDays, habit.completions]);
|
||||
|
||||
for (let i = numDays - 1; i >= 0; i--) {
|
||||
const date = new Date(today);
|
||||
@@ -23,31 +30,34 @@ const MiniGrid = ({ habit, onUpdate }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex gap-1 overflow-x-auto grid-scroll pb-2">
|
||||
<div ref={scrollRef} className="flex gap-1 overflow-x-auto grid-scroll pb-2">
|
||||
{days.map((date, index) => {
|
||||
const dateStr = formatDate(date);
|
||||
const isCompleted = habit.completions.includes(dateStr);
|
||||
const intensity = isCompleted ? getColorIntensity(habit.completions, dateStr) : 0;
|
||||
const isTodayCell = isToday(date);
|
||||
|
||||
const dayLetter = date.toLocaleDateString('en-US', { weekday: 'short' })[0];
|
||||
|
||||
return (
|
||||
<motion.button
|
||||
key={index}
|
||||
whileHover={{ scale: 0.9 }}
|
||||
whileTap={{ scale: 0.5 }}
|
||||
onClick={(e) => handleCellClick(e, date)}
|
||||
className="habit-cell flex w-8 h-8 rounded-2xl transition-all"
|
||||
style={{
|
||||
backgroundColor: isCompleted
|
||||
? habit.color
|
||||
: 'transparent',
|
||||
opacity: isCompleted ? 0.3 + (intensity * 0.7) : 1,
|
||||
border: isTodayCell
|
||||
? `2px solid ${habit.color}`
|
||||
: `1px solid ${habit.color}20`,
|
||||
}}
|
||||
title={dateStr}
|
||||
/>
|
||||
<div key={index} className="flex flex-col items-center">
|
||||
<motion.button
|
||||
whileHover={{ scale: 0.9 }}
|
||||
whileTap={{ scale: 0.5 }}
|
||||
onClick={(e) => handleCellClick(e, date)}
|
||||
className={`habit-cell flex w-8 h-8 transition-all ${isTodayCell ? 'rounded-md' : 'rounded-2xl'}`}
|
||||
style={{
|
||||
backgroundColor: isCompleted
|
||||
? habit.color
|
||||
: 'transparent',
|
||||
opacity: isCompleted ? 0.3 + (intensity * 0.7) : 1,
|
||||
border: isTodayCell
|
||||
? `2px solid ${habit.color}`
|
||||
: `1px solid ${habit.color}20`,
|
||||
}}
|
||||
title={dateStr}
|
||||
/>
|
||||
<span className="text-[10px] text-muted-foreground mt-1">{dayLetter}</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user