diff --git a/apps/web/app/(app)/page.tsx b/apps/web/app/(app)/page.tsx index 053ba409..dc80dd1f 100644 --- a/apps/web/app/(app)/page.tsx +++ b/apps/web/app/(app)/page.tsx @@ -1,9 +1,10 @@ "use client" -import { useState, useCallback, useEffect } from "react" +import { useState, useCallback, useEffect, useMemo } from "react" import { useQueryState } from "nuqs" import { Header } from "@/components/header" import { ChatSidebar, HomeChatComposer } from "@/components/chat" +import { DashboardView } from "@/components/dashboard-view" import { MemoriesGrid } from "@/components/memories-grid" import { GraphLayoutView } from "@/components/graph-layout-view" import { IntegrationsView } from "@/components/integrations-view" @@ -44,6 +45,7 @@ import { pluginsPanelParam, type IntegrationParamValue, } from "@/lib/search-params" +import { getChatSpaceDisplayLabel } from "@/lib/chat-space-label" type DocumentsResponse = z.infer type DocumentWithMemories = DocumentsResponse["documents"][0] @@ -105,6 +107,14 @@ export default function NewPage() { (selectedProjectTag !== undefined && novaContainerTags.includes(selectedProjectTag)) const { allProjects } = useContainerTags() + const dashboardSpaceLabel = useMemo( + () => + getChatSpaceDisplayLabel({ + selectedProject, + allProjects, + }), + [selectedProject, allProjects], + ) const emptyStateSpaceName = !isNovaSpaces && selectedProjectTag ? selectedProjectTag === DEFAULT_PROJECT_ID @@ -150,7 +160,10 @@ export default function NewPage() { "integration", integrationParam, ) - const [pluginsPanelFromUrl] = useQueryState("plugins", pluginsPanelParam) + const [pluginsPanelFromUrl, setPluginsPanel] = useQueryState( + "plugins", + pluginsPanelParam, + ) useEffect(() => { if (integrationFromUrl || pluginsPanelFromUrl === true) { @@ -446,6 +459,11 @@ export default function NewPage() { [setViewMode, setIntegration], ) + const handleOpenPlugins = useCallback(() => { + void setViewMode("integrations") + void setPluginsPanel(true) + }, [setViewMode, setPluginsPanel]) + const handleAddMemory = useCallback( (tab: "note" | "link") => { analytics.addDocumentModalOpened() @@ -456,6 +474,8 @@ export default function NewPage() { const isChatView = viewMode === "chat" const isGraphMode = viewMode === "graph" && !isMobile + const isDashboardShell = + viewMode === "dashboard" || (viewMode === "graph" && isMobile) // Animated gradient — commented for now (use with useSyncExternalStore + helpers above). // const viewportWidth = useSyncExternalStore( @@ -509,7 +529,7 @@ export default function NewPage() { layout="page" isChatOpen setIsChatOpen={(open) => { - if (!open) void setViewMode("list") + if (!open) void setViewMode("dashboard") }} queuedMessage={queuedChatSeed} onConsumeQueuedMessage={consumeQueuedChat} @@ -526,11 +546,11 @@ export default function NewPage() {
- ) : ( + ) : viewMode === "list" ? (
+ ) : ( + + + Graph view is available on desktop. + {" "} + Use a larger screen for the full graph, or keep working + from this home view. + + ) : undefined + } + highlights={highlightsData?.highlights ?? []} + isLoadingHighlights={isLoadingHighlights} + onAddMemory={handleAddMemory} + onOpenSearch={() => { + analytics.searchOpened({ source: "header" }) + setIsSearchOpen(true) + }} + onOpenIntegrations={handleOpenIntegrations} + onOpenPlugins={handleOpenPlugins} + onNavigateToMemories={() => void setViewMode("list")} + onOpenDocument={handleOpenDocument} + onHighlightsChat={handleHighlightsChat} + onHighlightsShowRelated={handleHighlightsShowRelated} + /> )} - {viewMode === "list" && ( + {isDashboardShell && (
{}} onKeyDown={handleKeyDown} isResponding={false} - activeStatus="Waiting for input..." + showStatusStrip={false} stackedToolbar={ <> void /** Model + space controls on one row with send; textarea full-width above */ stackedToolbar?: ReactNode + /** Nova status row + chain-of-thought toggle (off for e.g. home composer) */ + showStatusStrip?: boolean } export default function ChatInput({ @@ -33,6 +35,7 @@ export default function ChatInput({ chainOfThoughtComponent, onExpandedChange, stackedToolbar, + showStatusStrip = true, }: ChatInputProps) { const [isMultiline, setIsMultiline] = useState(false) const [isExpanded, setIsExpanded] = useState(false) @@ -55,57 +58,69 @@ export default function ChatInput({ -
- {chainOfThoughtComponent} -
- + style={{ + zIndex: isExpanded ? 50 : 0, + }} + > + {chainOfThoughtComponent} +
+ + + ) : null} {stackedToolbar ? (