mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-12 20:57:42 +02:00
[eric] onboarding: HOVER a starter opens the composer (translucent preview), leave closes it, CLICK locks the query in to send
This commit is contained in:
@@ -76,7 +76,6 @@ const ChatInput = forwardRef<ChatInputHandle, Props>(({ onSend, disabled, mode,
|
||||
prefilledRef.current = prefillPrompt;
|
||||
editor.style.opacity = '0.5';
|
||||
editor.style.transition = 'opacity 0.15s';
|
||||
editor.focus();
|
||||
const solidify = () => {
|
||||
editor.style.opacity = '';
|
||||
editor.removeEventListener('keydown', solidify);
|
||||
|
||||
@@ -73,7 +73,7 @@ interface DashboardCanvasProps {
|
||||
onNewAgent: () => void;
|
||||
onToolbarCancel: () => void;
|
||||
onToolbarSend: (...args: any[]) => void;
|
||||
onStarterPrefill: (prompt: string) => void;
|
||||
onStarter: (action: 'hover' | 'leave' | 'commit', prompt?: string) => void;
|
||||
toolbarPrefill?: string;
|
||||
onAddView: (outputId: string) => void;
|
||||
onHistoryResume: (sessionId: string) => void;
|
||||
@@ -132,7 +132,7 @@ const DashboardCanvas: React.FC<DashboardCanvasProps> = ({
|
||||
onNewAgent,
|
||||
onToolbarCancel,
|
||||
onToolbarSend,
|
||||
onStarterPrefill,
|
||||
onStarter,
|
||||
toolbarPrefill,
|
||||
onAddView,
|
||||
onHistoryResume,
|
||||
@@ -219,7 +219,7 @@ const DashboardCanvas: React.FC<DashboardCanvasProps> = ({
|
||||
/>
|
||||
|
||||
{sessionList.length === 0 && Object.keys(viewCards).length === 0 && Object.keys(browserCards).length === 0 ? (
|
||||
<DashboardEmptyState c={c} onLaunch={onToolbarSend} onPrefill={onStarterPrefill} />
|
||||
<DashboardEmptyState c={c} onLaunch={onToolbarSend} onStarter={onStarter} />
|
||||
) : (
|
||||
<div
|
||||
ref={canvas.contentRef}
|
||||
|
||||
@@ -62,9 +62,10 @@ const STARTER_CATEGORIES: StarterCategory[] = [
|
||||
const DashboardEmptyState: React.FC<{
|
||||
c: ClaudeTokens;
|
||||
onLaunch?: (prompt: string, mode: string, model: string) => void;
|
||||
// Open the composer with the prompt typed in (unsent) so the user hits send.
|
||||
onPrefill?: (prompt: string) => void;
|
||||
}> = ({ c, onLaunch, onPrefill }) => {
|
||||
// hover = preview-open the composer (translucent), leave = close it,
|
||||
// commit = lock it open so the user can move to send.
|
||||
onStarter?: (action: 'hover' | 'leave' | 'commit', prompt?: string) => void;
|
||||
}> = ({ c, onLaunch, onStarter }) => {
|
||||
// The host hides Dashboard with visibility:hidden (not display:none), which keeps
|
||||
// CSS animations ticking; gate on active so the shimmer only burns while watched.
|
||||
const active = useDashboardActive();
|
||||
@@ -81,17 +82,17 @@ const DashboardEmptyState: React.FC<{
|
||||
// model connected); otherwise fall back to the plain hint.
|
||||
const showChips = !!onLaunch && canRun;
|
||||
|
||||
const isAppBuilder = currentCategory?.target === 'app-builder';
|
||||
|
||||
// Click commits the query into the composer (locks it open); the user then sends.
|
||||
const launch = (prompt: string) => {
|
||||
if (launching) return;
|
||||
// Build prompts open the App Builder (live preview) with the prompt auto-sent.
|
||||
if (currentCategory?.target === 'app-builder') {
|
||||
if (isAppBuilder) {
|
||||
navigate(`/apps/new?prompt=${encodeURIComponent(prompt)}`);
|
||||
return;
|
||||
}
|
||||
// Open the composer with the prompt typed in, unsent: the user sees the chat
|
||||
// open with their message ready and clicks send. Falls back to direct launch.
|
||||
if (onPrefill) {
|
||||
onPrefill(prompt);
|
||||
if (onStarter) {
|
||||
onStarter('commit', prompt);
|
||||
return;
|
||||
}
|
||||
if (!onLaunch) return;
|
||||
@@ -201,12 +202,16 @@ const DashboardEmptyState: React.FC<{
|
||||
>
|
||||
<ArrowLeft size={15} /> back
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.9, width: '100%', maxWidth: 480 }}>
|
||||
<Box
|
||||
onMouseLeave={() => { if (!isAppBuilder) onStarter?.('leave'); }}
|
||||
sx={{ display: 'flex', flexDirection: 'column', gap: 0.9, width: '100%', maxWidth: 480 }}
|
||||
>
|
||||
{currentPrompts.map((prompt) => (
|
||||
<Box
|
||||
component="button"
|
||||
key={prompt}
|
||||
onClick={() => launch(prompt)}
|
||||
onMouseEnter={() => { if (!isAppBuilder) onStarter?.('hover', prompt); }}
|
||||
disabled={launching}
|
||||
sx={{
|
||||
textAlign: 'left',
|
||||
|
||||
@@ -159,16 +159,28 @@ export function useDashboardController(dashboardId: string, isActive: boolean) {
|
||||
setSearchPaletteOpen,
|
||||
});
|
||||
|
||||
// Starter-prompt prefill: opens the composer with the prompt typed in (unsent),
|
||||
// so the user reviews and hits send. Bump a nonce so re-clicking the same prompt
|
||||
// (after editing/clearing) still re-seeds. Cleared when the composer closes.
|
||||
// Starter-prompt preview: HOVER opens the composer with the prompt typed in
|
||||
// (translucent, unsent); leaving closes it again; CLICK locks it open so the
|
||||
// user can move to the send button without it vanishing. Then they hit send.
|
||||
const [toolbarPrefill, setToolbarPrefill] = useState<string | undefined>(undefined);
|
||||
const handleStarterPrefill = useCallback((prompt: string) => {
|
||||
setToolbarPrefill(prompt);
|
||||
setToolbarOpen(true);
|
||||
const starterLockedRef = useRef(false);
|
||||
const handleStarter = useCallback((action: 'hover' | 'leave' | 'commit', prompt?: string) => {
|
||||
if (action === 'hover' && prompt) {
|
||||
setToolbarPrefill(prompt);
|
||||
setToolbarOpen(true);
|
||||
} else if (action === 'commit' && prompt) {
|
||||
starterLockedRef.current = true;
|
||||
setToolbarPrefill(prompt);
|
||||
setToolbarOpen(true);
|
||||
} else if (action === 'leave' && !starterLockedRef.current) {
|
||||
setToolbarOpen(false);
|
||||
}
|
||||
}, [setToolbarOpen]);
|
||||
useEffect(() => {
|
||||
if (!toolbarOpen && toolbarPrefill) setToolbarPrefill(undefined);
|
||||
if (!toolbarOpen) {
|
||||
starterLockedRef.current = false;
|
||||
if (toolbarPrefill) setToolbarPrefill(undefined);
|
||||
}
|
||||
}, [toolbarOpen, toolbarPrefill]);
|
||||
|
||||
useDashboardClipboard({
|
||||
@@ -266,7 +278,7 @@ export function useDashboardController(dashboardId: string, isActive: boolean) {
|
||||
neighborDirections, toolbarOpen, searchPaletteOpen, newAgentBounce,
|
||||
toolbarRef, spawnOriginsRef, revealSpawnedRef, measuredHeightsRef, getCanvasState,
|
||||
toolbarPrefill,
|
||||
onStarterPrefill: handleStarterPrefill,
|
||||
onStarter: handleStarter,
|
||||
onViewportMouseDown: handleViewportMouseDown,
|
||||
onViewportMouseMove: handleViewportMouseMove,
|
||||
onViewportMouseUp: handleViewportMouseUp,
|
||||
|
||||
Reference in New Issue
Block a user