feat(mindspace): gate published page delivery
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { ChangeEvent, useCallback, useEffect, useLayoutEffect, useRef, useState, type ClipboardEvent } from 'react';
|
||||
import { BrainCircuit, Database } from 'lucide-react';
|
||||
import { useNetworkStatus } from '../hooks/useNetworkStatus';
|
||||
import { openAvatarPicker } from '../utils/userAvatar';
|
||||
import { CHAT_SKILL_OPTIONS, filterChatSkills } from '../utils/chatSkills';
|
||||
@@ -184,6 +185,7 @@ export function ChatPanel({
|
||||
options?: {
|
||||
messageId?: string;
|
||||
forceDeepReasoning?: boolean;
|
||||
pgRequired?: boolean;
|
||||
selectedChatSkill?: string;
|
||||
fileAttachments?: ChatFileAttachment[];
|
||||
},
|
||||
@@ -216,6 +218,8 @@ export function ChatPanel({
|
||||
const [plazaPublishSource, setPlazaPublishSource] = useState<Message | null>(null);
|
||||
const [voiceNotice, setVoiceNotice] = useState<string | null>(null);
|
||||
const [forceDeepReasoning, setForceDeepReasoning] = useState(false);
|
||||
const [pgRequired, setPgRequired] = useState(false);
|
||||
const [chatControlOnboardingStep, setChatControlOnboardingStep] = useState<0 | 1 | 2 | null>(null);
|
||||
const [pendingImages, setPendingImages] = useState<PendingChatImage[]>([]);
|
||||
const [pendingFiles, setPendingFiles] = useState<PendingChatFile[]>([]);
|
||||
const [uploadingImage, setUploadingImage] = useState(false);
|
||||
@@ -293,6 +297,16 @@ export function ChatPanel({
|
||||
nearBottomRef.current = true;
|
||||
}, [session?.id]);
|
||||
|
||||
useEffect(() => {
|
||||
setChatControlOnboardingStep(0);
|
||||
const timers = [
|
||||
window.setTimeout(() => setChatControlOnboardingStep(1), 2_200),
|
||||
window.setTimeout(() => setChatControlOnboardingStep(2), 4_400),
|
||||
window.setTimeout(() => setChatControlOnboardingStep(null), 6_600),
|
||||
];
|
||||
return () => timers.forEach((timer) => window.clearTimeout(timer));
|
||||
}, [session?.id]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const container = mainRef.current;
|
||||
if (!container) return;
|
||||
@@ -730,6 +744,7 @@ export function ChatPanel({
|
||||
await onSubmit(trimmed, imagesToSend, previewImagesToSend, {
|
||||
messageId: outgoingMessageId,
|
||||
forceDeepReasoning,
|
||||
pgRequired,
|
||||
selectedChatSkill,
|
||||
fileAttachments: fileAttachmentsToSend,
|
||||
});
|
||||
@@ -758,6 +773,7 @@ export function ChatPanel({
|
||||
suppressVoiceUpdateRef.current = false;
|
||||
}, [
|
||||
forceDeepReasoning,
|
||||
pgRequired,
|
||||
input,
|
||||
onSubmit,
|
||||
onUploadFile,
|
||||
@@ -1189,6 +1205,7 @@ export function ChatPanel({
|
||||
<ChatSkillPicker
|
||||
skills={chatSkills}
|
||||
disabled={voiceDisabled}
|
||||
onboardingActive={chatControlOnboardingStep === 0}
|
||||
onSelect={submitText}
|
||||
onPrefill={(prompt, skillId) => {
|
||||
pendingSkillRef.current = skillId ?? null;
|
||||
@@ -1196,23 +1213,38 @@ export function ChatPanel({
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{!showHomeWelcome && (
|
||||
<label
|
||||
className={`chat-deep-reasoning-toggle${forceDeepReasoning ? ' is-active' : ''}`}
|
||||
title="勾选后,本轮消息使用深度推理完成"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={forceDeepReasoning}
|
||||
disabled={voiceDisabled}
|
||||
onChange={(event) => setForceDeepReasoning(event.target.checked)}
|
||||
/>
|
||||
<span className="chat-deep-reasoning-toggle-label" aria-hidden="true">
|
||||
<span>深度</span>
|
||||
<span>推理</span>
|
||||
</span>
|
||||
</label>
|
||||
)}
|
||||
<label
|
||||
className={`chat-deep-reasoning-toggle${pgRequired ? ' is-active' : ''}${chatControlOnboardingStep === 1 ? ' chat-control-onboarding-active' : ''}`}
|
||||
title="勾选后,本轮生成的可保存数据必须使用你的专属 PostgreSQL 数据空间"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={pgRequired}
|
||||
disabled={voiceDisabled}
|
||||
aria-label="使用 PostgreSQL 数据空间"
|
||||
onChange={(event) => setPgRequired(event.target.checked)}
|
||||
/>
|
||||
<Database className="chat-deep-reasoning-toggle-icon" aria-hidden="true" />
|
||||
{chatControlOnboardingStep === 1 && (
|
||||
<span className="chat-control-onboarding-tip" role="status">需要长期使用的数据,放进专属空间</span>
|
||||
)}
|
||||
</label>
|
||||
<label
|
||||
className={`chat-deep-reasoning-toggle${forceDeepReasoning ? ' is-active' : ''}${chatControlOnboardingStep === 2 ? ' chat-control-onboarding-active' : ''}`}
|
||||
title="勾选后,本轮消息使用深度推理完成"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={forceDeepReasoning}
|
||||
disabled={voiceDisabled}
|
||||
aria-label="使用深度推理"
|
||||
onChange={(event) => setForceDeepReasoning(event.target.checked)}
|
||||
/>
|
||||
<BrainCircuit className="chat-deep-reasoning-toggle-icon" aria-hidden="true" />
|
||||
{chatControlOnboardingStep === 2 && (
|
||||
<span className="chat-control-onboarding-tip" role="status">复杂问题,开启深度推理</span>
|
||||
)}
|
||||
</label>
|
||||
{chatState === 'streaming' ? (
|
||||
<button type="button" className="danger-btn chat-input-action" onClick={() => void onStop()}>
|
||||
停止
|
||||
|
||||
@@ -5,11 +5,13 @@ import { ChatSkillIcon } from './ChatSkillIcons';
|
||||
export function ChatSkillPicker({
|
||||
skills,
|
||||
disabled,
|
||||
onboardingActive = false,
|
||||
onSelect,
|
||||
onPrefill,
|
||||
}: {
|
||||
skills: ChatSkillOption[];
|
||||
disabled?: boolean;
|
||||
onboardingActive?: boolean;
|
||||
onSelect: (prompt: string, skillId?: string) => void | Promise<void>;
|
||||
onPrefill?: (prompt: string, skillId?: string) => void;
|
||||
}) {
|
||||
@@ -50,7 +52,7 @@ export function ChatSkillPicker({
|
||||
<div className={`chat-skill-picker${open ? ' open' : ''}`} ref={wrapRef}>
|
||||
<button
|
||||
type="button"
|
||||
className="chat-skill-trigger"
|
||||
className={`chat-skill-trigger${onboardingActive ? ' chat-control-onboarding-active' : ''}`}
|
||||
disabled={disabled}
|
||||
aria-expanded={open}
|
||||
aria-haspopup="menu"
|
||||
@@ -59,6 +61,9 @@ export function ChatSkillPicker({
|
||||
>
|
||||
<ChatSkillIcon id="spark" className="chat-skill-trigger-icon" />
|
||||
<span className="chat-skill-trigger-label">skill</span>
|
||||
{onboardingActive && (
|
||||
<span className="chat-control-onboarding-tip" role="status">点击 Skill,更快捷完成任务</span>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{open && (
|
||||
|
||||
@@ -547,6 +547,7 @@ export function ChatView({
|
||||
{
|
||||
messageId: options?.messageId,
|
||||
forceDeepReasoning: options?.forceDeepReasoning,
|
||||
pgRequired: options?.pgRequired,
|
||||
selectedChatSkill: options?.selectedChatSkill,
|
||||
fileAttachments: options?.fileAttachments,
|
||||
},
|
||||
|
||||
@@ -147,6 +147,7 @@ export function SpaceChatPanel({
|
||||
...context,
|
||||
messageId: options?.messageId,
|
||||
forceDeepReasoning: options?.forceDeepReasoning,
|
||||
pgRequired: options?.pgRequired,
|
||||
fileAttachments: options?.fileAttachments,
|
||||
},
|
||||
imageUrls,
|
||||
@@ -158,6 +159,7 @@ export function SpaceChatPanel({
|
||||
mindspaceContext: context,
|
||||
messageId: options?.messageId,
|
||||
forceDeepReasoning: options?.forceDeepReasoning,
|
||||
pgRequired: options?.pgRequired,
|
||||
fileAttachments: options?.fileAttachments,
|
||||
},
|
||||
imageUrls,
|
||||
|
||||
Reference in New Issue
Block a user