From 864051a65b6cff62ffd14959f02ce01498be8ad5 Mon Sep 17 00:00:00 2001 From: ddshi <8811906+ddshi@user.noreply.gitee.com> Date: Sat, 14 Feb 2026 20:20:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E5=92=8C=E8=BE=93=E5=85=A5=E6=A1=86=E4=BA=A4?= =?UTF-8?q?=E4=BA=92=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 纪念日/提醒列表添加动态底部填充,避免被 AI 输入框遮挡 - AI 输入框在弹窗和右键菜单打开时自动隐藏 - 优化输入框样式,提升在浅色背景上的可见度 Co-Authored-By: Claude Opus 4.6 --- src/components/ai/FloatingAIChat.tsx | 21 ++++++++---- .../anniversary/AnniversaryList.tsx | 33 +++++++++++++++++-- src/components/reminder/ReminderList.tsx | 32 +++++++++++++++++- src/pages/HomePage.tsx | 6 ++-- 4 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/components/ai/FloatingAIChat.tsx b/src/components/ai/FloatingAIChat.tsx index 68bbdb7..fa09643 100644 --- a/src/components/ai/FloatingAIChat.tsx +++ b/src/components/ai/FloatingAIChat.tsx @@ -27,9 +27,10 @@ import { notifications } from '@mantine/notifications'; interface FloatingAIChatProps { onEventCreated?: () => void; + hidden?: boolean; } -export function FloatingAIChat({ onEventCreated }: FloatingAIChatProps) { +export function FloatingAIChat({ onEventCreated, hidden = false }: FloatingAIChatProps) { const [isFocused, setIsFocused] = useState(false); const [message, setMessage] = useState(''); const [loading, setLoading] = useState(false); @@ -212,6 +213,11 @@ export function FloatingAIChat({ onEventCreated }: FloatingAIChatProps) { return editForm.type === 'anniversary' ? '纪念日' : '提醒'; }; + // 当 hidden 为 true 时,不渲染组件 + if (hidden) { + return null; + } + return ( <> {/* 遮罩层 */} @@ -246,13 +252,13 @@ export function FloatingAIChat({ onEventCreated }: FloatingAIChatProps) { e.type === 'anniversary'); const showHolidays = useAppStore((state) => state.settings?.showHolidays ?? true); const scrollContainerRef = useRef(null); + const [bottomPadding, setBottomPadding] = useState(0); + + // 检测列表是否可滚动,如果是则添加底部填充避免被 AI 输入框遮挡 + useEffect(() => { + const updatePadding = () => { + const container = scrollContainerRef.current; + if (!container) return; + + // 判断是否可滚动(内容高度 > 容器高度) + const isScrollable = container.scrollHeight > container.clientHeight; + // 底部填充高度:AI 输入框高度(约50px) + 底部间距(48px) + 额外缓冲(20px) + setBottomPadding(isScrollable ? 120 : 0); + }; + + // 延迟执行确保 DOM 完全渲染 + const timer = setTimeout(updatePadding, 100); + + // 监听容器和内容变化 + const container = scrollContainerRef.current; + if (container) { + const observer = new ResizeObserver(updatePadding); + observer.observe(container); + return () => { + observer.disconnect(); + clearTimeout(timer); + }; + } + return () => clearTimeout(timer); + }, [events]); // 滚动条样式 - 仅在悬停时显示 const scrollbarStyle = ` @@ -179,7 +208,7 @@ export function AnniversaryList({ events, onEventClick, onAddClick }: Anniversar ref={scrollContainerRef} onWheel={handleWheel} className="anniversary-scroll" - style={{ flex: 1, overflowY: 'auto', minHeight: 0 }} + style={{ flex: 1, overflowY: 'auto', minHeight: 0, paddingBottom: bottomPadding }} > {/* 内置节假日 */} diff --git a/src/components/reminder/ReminderList.tsx b/src/components/reminder/ReminderList.tsx index 31c41ec..022c4f0 100644 --- a/src/components/reminder/ReminderList.tsx +++ b/src/components/reminder/ReminderList.tsx @@ -1,4 +1,4 @@ -import { useMemo, useRef, useState } from 'react'; +import { useMemo, useRef, useState, useEffect } from 'react'; import { Stack, Text, @@ -43,6 +43,35 @@ export function ReminderList({ }: ReminderListProps) { const navigate = useNavigate(); const scrollContainerRef = useRef(null); + const [bottomPadding, setBottomPadding] = useState(0); + + // 检测列表是否可滚动,如果是则添加底部填充避免被 AI 输入框遮挡 + useEffect(() => { + const updatePadding = () => { + const container = scrollContainerRef.current; + if (!container) return; + + // 判断是否可滚动(内容高度 > 容器高度) + const isScrollable = container.scrollHeight > container.clientHeight; + // 底部填充高度:AI 输入框高度(约50px) + 底部间距(48px) + 额外缓冲(20px) + setBottomPadding(isScrollable ? 120 : 0); + }; + + // 延迟执行确保 DOM 完全渲染 + const timer = setTimeout(updatePadding, 100); + + // 监听容器和内容变化 + const container = scrollContainerRef.current; + if (container) { + const observer = new ResizeObserver(updatePadding); + observer.observe(container); + return () => { + observer.disconnect(); + clearTimeout(timer); + }; + } + return () => clearTimeout(timer); + }, [events]); // 分类折叠状态 const [collapsed, setCollapsed] = useState({ @@ -278,6 +307,7 @@ export function ReminderList({ flex: 1, overflowY: 'auto', minHeight: 0, + paddingBottom: bottomPadding, }} > diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 5aeb8fc..16277e7 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -22,6 +22,7 @@ import { FixedCalendar } from '../components/common/FixedCalendar'; import { TimePicker } from '../components/common/TimePicker'; import { useNavigate } from 'react-router-dom'; import { useAppStore } from '../stores'; +import { useContextMenuStore } from '../stores/contextMenu'; import { AnniversaryList } from '../components/anniversary/AnniversaryList'; import { ReminderList } from '../components/reminder/ReminderList'; import { NoteEditor } from '../components/note/NoteEditor'; @@ -34,6 +35,7 @@ export function HomePage() { const navigate = useNavigate(); const user = useAppStore((state) => state.user); const logout = useAppStore((state) => state.logout); + const openEventId = useContextMenuStore((state) => state.openEventId); const checkAuth = useAppStore((state) => state.checkAuth); const events = useAppStore((state) => state.events); const fetchEvents = useAppStore((state) => state.fetchEvents); @@ -391,8 +393,6 @@ export function HomePage() { onDateChange={handleDateChange} onPriorityChange={handlePriorityChange} /> - {/* 底部空白区域 - 避免被 AI 输入框遮挡 */} - {/* Right column - Note */} @@ -402,7 +402,7 @@ export function HomePage() { {/* AI Chat - Floating */} - +