forked from akai/readest
feat(ai): AI reading assistant phase 2.1 (minor UI/UX updates) (#3059)
* refactor(ai): remove chat icons from conversation list items * feat(ai): add scroll-to-bottom button with animations and dynamic spacer * fix(ai): align connection status icon with text in settings * feat(ai): scroll to bottom on chat panel open and improve scroll behavior * feat(ai): add loading overlay with blur transition for chat history * feat(ai): pass loading state through component chain for history loading
This commit is contained in:
@@ -84,7 +84,12 @@ const AIAssistantChat = ({
|
||||
currentPage: number;
|
||||
onResetIndex: () => void;
|
||||
}) => {
|
||||
const { activeConversationId, messages: storedMessages, addMessage } = useAIChatStore();
|
||||
const {
|
||||
activeConversationId,
|
||||
messages: storedMessages,
|
||||
addMessage,
|
||||
isLoadingHistory,
|
||||
} = useAIChatStore();
|
||||
|
||||
// use a ref to keep up-to-date options without triggering re-renders of the runtime
|
||||
const optionsRef = useRef({
|
||||
@@ -153,41 +158,55 @@ const AIAssistantChat = ({
|
||||
adapter={adapter}
|
||||
historyAdapter={historyAdapter}
|
||||
onResetIndex={onResetIndex}
|
||||
isLoadingHistory={isLoadingHistory}
|
||||
hasActiveConversation={!!activeConversationId}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// separate component to ensure useLocalRuntime is always called with a valid adapter
|
||||
const AIAssistantWithRuntime = ({
|
||||
adapter,
|
||||
historyAdapter,
|
||||
onResetIndex,
|
||||
isLoadingHistory,
|
||||
hasActiveConversation,
|
||||
}: {
|
||||
adapter: NonNullable<ReturnType<typeof createTauriAdapter>>;
|
||||
historyAdapter?: ThreadHistoryAdapter;
|
||||
onResetIndex: () => void;
|
||||
isLoadingHistory: boolean;
|
||||
hasActiveConversation: boolean;
|
||||
}) => {
|
||||
const runtime = useLocalRuntime(adapter, {
|
||||
adapters: historyAdapter ? { history: historyAdapter } : undefined,
|
||||
});
|
||||
|
||||
// ensure runtime is available before providing it
|
||||
if (!runtime) return null;
|
||||
|
||||
return (
|
||||
<AssistantRuntimeProvider runtime={runtime}>
|
||||
<ThreadWrapper onResetIndex={onResetIndex} />
|
||||
<ThreadWrapper
|
||||
onResetIndex={onResetIndex}
|
||||
isLoadingHistory={isLoadingHistory}
|
||||
hasActiveConversation={hasActiveConversation}
|
||||
/>
|
||||
</AssistantRuntimeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
// inner component that uses useAssistantRuntime (must be inside provider)
|
||||
const ThreadWrapper = ({ onResetIndex }: { onResetIndex: () => void }) => {
|
||||
const ThreadWrapper = ({
|
||||
onResetIndex,
|
||||
isLoadingHistory,
|
||||
hasActiveConversation,
|
||||
}: {
|
||||
onResetIndex: () => void;
|
||||
isLoadingHistory: boolean;
|
||||
hasActiveConversation: boolean;
|
||||
}) => {
|
||||
const [sources, setSources] = useState(getLastSources());
|
||||
const assistantRuntime = useAssistantRuntime();
|
||||
const { setActiveConversation } = useAIChatStore();
|
||||
|
||||
// poll for sources updates (adapter stores them)
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setSources(getLastSources());
|
||||
@@ -202,7 +221,15 @@ const ThreadWrapper = ({ onResetIndex }: { onResetIndex: () => void }) => {
|
||||
assistantRuntime.switchToNewThread();
|
||||
}, [assistantRuntime, setActiveConversation]);
|
||||
|
||||
return <Thread sources={sources} onClear={handleClear} onResetIndex={onResetIndex} />;
|
||||
return (
|
||||
<Thread
|
||||
sources={sources}
|
||||
onClear={handleClear}
|
||||
onResetIndex={onResetIndex}
|
||||
isLoadingHistory={isLoadingHistory}
|
||||
hasActiveConversation={hasActiveConversation}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const AIAssistant = ({ bookKey }: AIAssistantProps) => {
|
||||
|
||||
@@ -153,8 +153,6 @@ const ChatHistoryView: React.FC<ChatHistoryViewProps> = ({ bookKey }) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
<LuMessageSquare className='text-base-content/40 mt-0.5 size-4 flex-shrink-0' />
|
||||
|
||||
<div className='min-w-0 flex-1'>
|
||||
{editingId === conversation.id ? (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user