fix: CSS class slide animation, mobile dot, flex task indicators

This commit is contained in:
mARTin 2026-03-04 08:54:37 +01:00
parent b3503d9e4d
commit 9fa646fa55
2 changed files with 36 additions and 62 deletions

View File

@ -719,6 +719,9 @@ h3 {
resize: none;
min-height: 1.5em;
padding-top: 2px; /* Align with icons */
display: flex;
align-items: flex-start;
gap: 4px;
}
/* Task Actions Visibility - Unified for Weekly and Time Grid */
@ -2736,46 +2739,23 @@ h3 {
background: #333;
}
/* --- VIEW TRANSITION ANIMATION (Day/Week Navigation Slide) --- */
/* --- SLIDE ANIMATION (Day/Week Navigation) --- */
/* Class-based animation that works on ALL browsers (no View Transitions API needed) */
@keyframes slideOutToLeft {
from { transform: translateX(0); }
to { transform: translateX(-100%); }
@keyframes navSlideInFromRight {
from { transform: translateX(40%); opacity: 0.3; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideInFromRight {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes slideOutToRight {
from { transform: translateX(0); }
to { transform: translateX(100%); }
}
@keyframes slideInFromLeft {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
@keyframes navSlideInFromLeft {
from { transform: translateX(-40%); opacity: 0.3; }
to { transform: translateX(0); opacity: 1; }
}
/* Week Grid Transition Group */
::view-transition-group(week-grid) {
animation-duration: 0.9s;
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
.slide-animate-next {
animation: navSlideInFromRight 0.35s cubic-bezier(0.25, 1, 0.5, 1) both;
}
/* Slide Next (Left) — content exits left, new enters from right */
[data-slide-direction="next"]::view-transition-old(week-grid) {
animation-name: slideOutToLeft;
}
[data-slide-direction="next"]::view-transition-new(week-grid) {
animation-name: slideInFromRight;
}
/* Slide Prev (Right) — content exits right, new enters from left */
[data-slide-direction="prev"]::view-transition-old(week-grid) {
animation-name: slideOutToRight;
}
[data-slide-direction="prev"]::view-transition-new(week-grid) {
animation-name: slideInFromLeft;
.slide-animate-prev {
animation: navSlideInFromLeft 0.35s cubic-bezier(0.25, 1, 0.5, 1) both;
}
/* Smooth View Transitions */

View File

@ -2087,27 +2087,30 @@ export default function WeeklyView() {
[tasks, cellDuration],
);
// Navigation handlers with proper slide animation
// Simplified: Immediate state update with slide-in animation to prevent blank flash
// Navigation handlers with CSS class-based slide animation (works in all browsers)
const gridRef = useRef<HTMLElement>(null);
const navigate = (
newDate: Date,
direction: "left" | "right",
type: "day" | "week",
) => {
if (typeof document !== "undefined" && "startViewTransition" in document) {
const doc = document as any;
doc.documentElement.dataset.slideDirection =
direction === "left" ? "next" : "prev";
doc.documentElement.dataset.navType = "week"; // Always use full-grid slide for both day and week
doc.startViewTransition(() => {
setCurrentWeekStart(newDate);
// setSlideDirection state is not strictly needed for global transition but keeping it clean
setSlideDirection(direction === "left" ? "next" : "prev");
});
} else {
setCurrentWeekStart(newDate);
const grid = gridRef.current;
if (grid) {
// Remove any existing animation class
grid.classList.remove("slide-animate-next", "slide-animate-prev");
// Trigger reflow to restart animation if same direction
void grid.offsetWidth;
// Add new animation class
grid.classList.add(direction === "left" ? "slide-animate-next" : "slide-animate-prev");
// Clean up after animation
const cleanup = () => {
grid.classList.remove("slide-animate-next", "slide-animate-prev");
grid.removeEventListener("animationend", cleanup);
};
grid.addEventListener("animationend", cleanup, { once: true });
}
setCurrentWeekStart(newDate);
setSlideDirection(direction === "left" ? "next" : "prev");
};
const goToPrevWeek = () =>
@ -3720,8 +3723,8 @@ export default function WeeklyView() {
<button className="p-1.5 rounded text-gray-500 active:bg-white active:shadow-sm" onClick={goToPrevDay} title="Previous Day">
<ChevronLeft size={16} />
</button>
<button className="px-3 py-1 text-xs font-bold text-gray-600 dark:text-gray-300 rounded active:bg-white active:shadow-sm" onClick={goToToday}>
Today
<button className="w-7 h-7 flex items-center justify-center text-gray-600 dark:text-gray-300 rounded active:bg-white active:shadow-sm" onClick={goToToday} title="Today">
<span style={{ fontSize: "8px" }}></span>
</button>
<button className="p-1.5 rounded text-gray-500 active:bg-white active:shadow-sm" onClick={goToNextDay} title="Next Day">
<ChevronLeft size={16} className="rotate-180" />
@ -4311,14 +4314,10 @@ export default function WeeklyView() {
{/* Day Columns */}
<main
ref={gridRef}
className={`weekly-days-grid cols-${viewDays}`}
data-slide-direction={slideDirection}
data-nav-type={viewDays > 1 ? "week" : "day"}
style={
{
viewTransitionName: viewDays > 1 ? "week-grid" : "none",
} as React.CSSProperties
}
>
{getVisibleDays().map((date, colIndex) => {
const todayMidnight = new Date();
@ -4330,11 +4329,6 @@ export default function WeeklyView() {
<div
key={date.toISOString()}
className={`weekly-day-column ${date.getDay() === 6 ? "is-sat" : ""} ${date.getDay() === 0 ? "is-sun" : ""} ${isToday ? "is-today" : ""} ${isPast ? "is-past" : ""}`}
style={
{
viewTransitionName: `day-${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`,
} as any
}
>
{/* Day Header */}
<header className="weekly-day-header" ref={colIndex === 0 ? dayHeaderRef : undefined}>