From 4f5d520834c57499094f01df3ae723c4711f16cc Mon Sep 17 00:00:00 2001 From: jonathan vergara Date: Fri, 13 Mar 2026 13:42:41 -0600 Subject: [PATCH 1/5] Keep Campaigns tab active when clicking a campaign; show drill-down in same tab Made-with: Cursor --- canvas/src/App.tsx | 6 +++--- canvas/src/components/CampaignDashboard.tsx | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/canvas/src/App.tsx b/canvas/src/App.tsx index ff8f16c..5e92f73 100644 --- a/canvas/src/App.tsx +++ b/canvas/src/App.tsx @@ -224,12 +224,12 @@ export function App() { ); } - // Campaigns tab: only show campaigns list (folders). Creations live in the Creations tab. - if (createViewportTab === 'campaigns') { + // Campaigns tab: show campaign list only at dashboard; when a campaign is selected, show drill-down in same tab. + if (createViewportTab === 'campaigns' && currentView === 'dashboard') { return ; } - // Creations tab: show creations hierarchy (creations → slides → iterations) + // Creations tab at dashboard, or either tab when drilled in: show creations hierarchy (creations → slides → iterations) switch (currentView) { case 'dashboard': return ( diff --git a/canvas/src/components/CampaignDashboard.tsx b/canvas/src/components/CampaignDashboard.tsx index aa7a931..cf723f3 100644 --- a/canvas/src/components/CampaignDashboard.tsx +++ b/canvas/src/components/CampaignDashboard.tsx @@ -599,7 +599,6 @@ export function CampaignDashboard() { const showNewCampaignModal = useCampaignStore((s) => s.showNewCampaignModal); const setShowNewCampaignModal = useCampaignStore((s) => s.setShowNewCampaignModal); - const setCreateViewportTab = useCampaignStore((s) => s.setCreateViewportTab); const [filterChannel, setFilterChannel] = useState('all'); const [sortKey, setSortKey] = useState('updatedAt'); @@ -682,7 +681,6 @@ export function CampaignDashboard() { }, [mosaicData]); const handleSelect = (item: DrillDownItem) => { - setCreateViewportTab('creations'); navigateToCampaign(item.id); }; From 628cb59d0d1ce13f4d656e1f6d557362ff2f00ae Mon Sep 17 00:00:00 2001 From: jonathan vergara Date: Fri, 13 Mar 2026 13:52:44 -0600 Subject: [PATCH 2/5] Make app the home/index screen: serve at / instead of /app/ Made-with: Cursor --- canvas/src/server/watcher.ts | 8 +++----- canvas/vite.config.ts | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/canvas/src/server/watcher.ts b/canvas/src/server/watcher.ts index f936ec2..5e7ebf7 100644 --- a/canvas/src/server/watcher.ts +++ b/canvas/src/server/watcher.ts @@ -174,11 +174,9 @@ export function fluidWatcherPlugin(workingDir: string): Plugin { return next(); } try { + // Home/index: let Vite serve the app at / if (pathname === '/') { - const html = await fs.readFile(path.join(templatesDir, 'index.html'), 'utf-8'); - res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); - res.end(html); - return; + return next(); } if (pathname === '/editor' || pathname.startsWith('/editor?')) { const html = await fs.readFile(path.join(templatesDir, 'editor.html'), 'utf-8'); @@ -423,7 +421,7 @@ export function fluidWatcherPlugin(workingDir: string): Plugin { ← Back to library diff --git a/canvas/vite.config.ts b/canvas/vite.config.ts index 3c011af..0cf2d48 100644 --- a/canvas/vite.config.ts +++ b/canvas/vite.config.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { fluidWatcherPlugin } from './src/server/watcher'; export default defineConfig({ - base: '/app/', + base: '/', plugins: [ react(), fluidWatcherPlugin('../.fluid/working'), From 2b78c7262c02a6ce07c9eeefbb4080fa0b5cd410 Mon Sep 17 00:00:00 2001 From: jonathan vergara Date: Fri, 13 Mar 2026 14:29:56 -0600 Subject: [PATCH 3/5] Fix landing: base /app/, redirect / to /app/ (keep template previews working) Made-with: Cursor --- canvas/src/server/watcher.ts | 6 ++++-- canvas/vite.config.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/canvas/src/server/watcher.ts b/canvas/src/server/watcher.ts index 5e7ebf7..82a1f0a 100644 --- a/canvas/src/server/watcher.ts +++ b/canvas/src/server/watcher.ts @@ -174,9 +174,11 @@ export function fluidWatcherPlugin(workingDir: string): Plugin { return next(); } try { - // Home/index: let Vite serve the app at / + // Home/index: redirect to React app at /app/ if (pathname === '/') { - return next(); + res.writeHead(302, { Location: '/app/' }); + res.end(); + return; } if (pathname === '/editor' || pathname.startsWith('/editor?')) { const html = await fs.readFile(path.join(templatesDir, 'editor.html'), 'utf-8'); diff --git a/canvas/vite.config.ts b/canvas/vite.config.ts index 0cf2d48..3c011af 100644 --- a/canvas/vite.config.ts +++ b/canvas/vite.config.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { fluidWatcherPlugin } from './src/server/watcher'; export default defineConfig({ - base: '/', + base: '/app/', plugins: [ react(), fluidWatcherPlugin('../.fluid/working'), From 19c0d78e57efbcbded025b048fa633735906fea3 Mon Sep 17 00:00:00 2001 From: jonathan vergara Date: Fri, 13 Mar 2026 14:33:33 -0600 Subject: [PATCH 4/5] Nav: Add Create (plus) first, rename Create to My Creations (masonry icon); add BuildHero Made-with: Cursor --- canvas/src/components/AppShell.tsx | 11 +- canvas/src/components/BuildHero.tsx | 270 ++++++++++++++++++++++++++++ canvas/src/components/LeftNav.tsx | 17 +- canvas/src/store/campaign.ts | 2 +- 4 files changed, 295 insertions(+), 5 deletions(-) create mode 100644 canvas/src/components/BuildHero.tsx diff --git a/canvas/src/components/AppShell.tsx b/canvas/src/components/AppShell.tsx index cbb1ef1..9858c0c 100644 --- a/canvas/src/components/AppShell.tsx +++ b/canvas/src/components/AppShell.tsx @@ -4,6 +4,7 @@ import { Breadcrumb } from './Breadcrumb'; import { LeftNav } from './LeftNav'; import { ChatSidebar } from './ChatSidebar'; import { VoiceGuide } from './VoiceGuide'; +import { BuildHero } from './BuildHero'; interface AppShellProps { /** @@ -71,7 +72,14 @@ export function AppShell({ leftSidebar, rightSidebar, children, onNewCreation }: case 'create': return (
- {/* Create viewport header: tabs row + breadcrumb row */} + +
+ ); + + case 'my-creations': + return ( +
+
- {/* Campaign drill-down content */}
{children}
diff --git a/canvas/src/components/BuildHero.tsx b/canvas/src/components/BuildHero.tsx new file mode 100644 index 0000000..ef4c918 --- /dev/null +++ b/canvas/src/components/BuildHero.tsx @@ -0,0 +1,270 @@ +import { useState } from 'react'; + +const CHIPS = [ + { id: 'db-auth', label: 'Add database and auth', icon: 'drop' }, + { id: 'nano-banana', label: 'Nano Banana 2', icon: 'brush' }, + { id: 'voice-apps', label: 'Create conversational voice apps', icon: 'waves' }, + { id: 'animate', label: 'Animate images wit', icon: 'doc', more: true }, +]; + +function SparkleIcon() { + return ( + + + + + + ); +} + +function GearIcon() { + return ( + + + + + ); +} + +function MicIcon() { + return ( + + + + + + + ); +} + +function PlusCircleIcon() { + return ( + + + + + + ); +} + +function ArrowLeftIcon() { + return ( + + + + + ); +} + +function ChipIcon({ type }: { type: string }) { + const color = '#44B2FF'; + if (type === 'drop') { + return ( + + + + ); + } + if (type === 'brush') { + return ( + + + + ); + } + if (type === 'waves') { + return ( + + + + ); + } + return ( + + + + + ); +} + +export function BuildHero() { + const [prompt, setPrompt] = useState(''); + + return ( +
+
+

+ Build your ideas with Gemini +

+ +
+ +
+
+