diff --git a/apps/marketing/public/app-icons/amp.svg b/apps/marketing/public/app-icons/amp.svg new file mode 100644 index 00000000000..dde8755df7e --- /dev/null +++ b/apps/marketing/public/app-icons/amp.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/apps/marketing/public/app-icons/copilot-white.svg b/apps/marketing/public/app-icons/copilot-white.svg new file mode 100644 index 00000000000..275b83930fc --- /dev/null +++ b/apps/marketing/public/app-icons/copilot-white.svg @@ -0,0 +1 @@ + diff --git a/apps/marketing/public/app-icons/copilot.svg b/apps/marketing/public/app-icons/copilot.svg new file mode 100644 index 00000000000..b52d96cffe1 --- /dev/null +++ b/apps/marketing/public/app-icons/copilot.svg @@ -0,0 +1 @@ + diff --git a/apps/marketing/public/app-icons/mastracode-white.svg b/apps/marketing/public/app-icons/mastracode-white.svg new file mode 100644 index 00000000000..b9d1810ce22 --- /dev/null +++ b/apps/marketing/public/app-icons/mastracode-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/marketing/public/app-icons/mastracode.svg b/apps/marketing/public/app-icons/mastracode.svg new file mode 100644 index 00000000000..865ced28da1 --- /dev/null +++ b/apps/marketing/public/app-icons/mastracode.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/marketing/public/app-icons/pi-white.svg b/apps/marketing/public/app-icons/pi-white.svg new file mode 100644 index 00000000000..df568173eb8 --- /dev/null +++ b/apps/marketing/public/app-icons/pi-white.svg @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/marketing/public/app-icons/pi.svg b/apps/marketing/public/app-icons/pi.svg new file mode 100644 index 00000000000..9f9c9eb0695 --- /dev/null +++ b/apps/marketing/public/app-icons/pi.svg @@ -0,0 +1,20 @@ + + + + + diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx index 2ec1dfebbb9..757736d8613 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx @@ -4,7 +4,7 @@ import { ExternalIdePopup } from "./components/ExternalIdePopup"; import { LeftSidebar } from "./components/LeftSidebar"; import { MainPanel } from "./components/MainPanel"; import { RightSidebar } from "./components/RightSidebar"; -import { WindowChrome } from "./components/WindowChrome"; +import { TabBar } from "./components/TabBar"; import type { AppMockupProps } from "./types"; export type { ActiveDemo } from "./types"; @@ -12,28 +12,17 @@ export type { ActiveDemo } from "./types"; export function AppMockup({ activeDemo = "Use Any Agents" }: AppMockupProps) { return (
-
+
- - -
+
- +
+ + +
diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/ExternalIdePopup/ExternalIdePopup.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/ExternalIdePopup/ExternalIdePopup.tsx index 871fe1d3ec5..1202997c6cf 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/ExternalIdePopup/ExternalIdePopup.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/ExternalIdePopup/ExternalIdePopup.tsx @@ -9,92 +9,84 @@ interface ExternalIdePopupProps { } export function ExternalIdePopup({ activeDemo }: ExternalIdePopupProps) { - const treeIconClassName = "size-3.5 shrink-0"; + const treeIconClassName = "size-3 shrink-0"; return ( -
+
-
+
-
-
-
+
+
+
- - External IDE + + Cursor — index.ts -
-
-
-
+
+
+
src
-
-
+
+
+ index.ts
-
+
utils.ts
-
+
types.ts
-
-
+
+
- import {"{"} Agent{" "} - {"}"} from{" "} - "ai" + import {"{"} Agent {"}"}{" "} + from{" "} + "ai"
- import {"{"} tools{" "} - {"}"} from{" "} - "./utils" + import {"{"} tools {"}"}{" "} + from{" "} + "./utils"
-
+
- const{" "} - agent ={" "} - new Agent({"{"} + const{" "} + agent ={" "} + new{" "} + Agent({"{"}
- model:{" "} - "claude-4", + model:{" "} + "claude-4",
- tools: [tools.read, + tools: [tools.read, tools.write]
{"}"})
diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/FileChangeItem/FileChangeItem.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/FileChangeItem/FileChangeItem.tsx index 88cd2dfe958..aba3347c9a5 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/FileChangeItem/FileChangeItem.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/FileChangeItem/FileChangeItem.tsx @@ -1,7 +1,7 @@ "use client"; import { - VscChevronRight, + VscChevronDown, VscDiffAdded, VscDiffModified, VscDiffRemoved, @@ -24,46 +24,48 @@ export function FileChangeItem({ type, }: FileChangeItemProps) { const isFolder = type === "folder"; - const Icon = isFolder - ? VscChevronRight - : type === "add" - ? VscDiffAdded - : type === "edit" - ? VscDiffModified - : type === "delete" - ? VscDiffRemoved - : VscDiffModified; - let iconColor = "text-muted-foreground/30"; if (isFolder) { - iconColor = "text-muted-foreground/24"; - } else if (type === "add") { - iconColor = "text-emerald-300/70"; - } else if (type === "edit") { - iconColor = "text-[#febc2e]/75"; - } else if (type === "delete") { - iconColor = "text-rose-300/75"; + return ( +
+ + {path} +
+ ); } + const Icon = + type === "add" + ? VscDiffAdded + : type === "delete" + ? VscDiffRemoved + : VscDiffModified; + + const iconColor = + type === "add" + ? "text-emerald-400/85" + : type === "delete" + ? "text-rose-400/85" + : "text-amber-300/85"; + return (
- - + + {path}
- {!isFolder && (add > 0 || del > 0) && ( - - {add > 0 && +{add}} - {del > 0 && -{del}} + {(add > 0 || del > 0) && ( + + {add > 0 && +{add}} + {del > 0 && −{del}} )}
diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/LeftSidebar/LeftSidebar.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/LeftSidebar/LeftSidebar.tsx index 72c6ff959b4..f1d93f50c89 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/LeftSidebar/LeftSidebar.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/LeftSidebar/LeftSidebar.tsx @@ -1,7 +1,13 @@ "use client"; import { motion } from "framer-motion"; -import { LuChevronDown, LuPlus, LuX } from "react-icons/lu"; +import { + LuChevronDown, + LuChevronRight, + LuLayers, + LuPlus, + LuZap, +} from "react-icons/lu"; import { PORTS, WORKSPACES } from "../../constants"; import type { ActiveDemo } from "../../types"; import { AsciiSpinner } from "../AsciiSpinner"; @@ -13,31 +19,22 @@ interface LeftSidebarProps { export function LeftSidebar({ activeDemo }: LeftSidebarProps) { return ( -
-
- +
+
+
+
+
-
-
- - superset - - (5) -
-
- - -
+
+ + +
-
+
+ + -
-
- -
-
-
- - new workspace - -
- - creating... - -
+
+ + + new workspace + + creating +
- {WORKSPACES.map((workspace) => { - const isFirstItem = workspace.name === "use any agents"; - const shouldHideActiveState = - isFirstItem && activeDemo === "Create Parallel Branches"; +
+ {WORKSPACES.map((workspace) => { + const isFirstItem = workspace.name === "use any agents"; + const shouldHideActiveState = + isFirstItem && activeDemo === "Create Parallel Branches"; - return ( - - ); - })} + return ( + + ); + })} +
+ +
+ +
+
+ +
+
+ +
-
-
-
- - Ports -
- 4 +
+
+ + ⌥ + + Ports + + 4 +
{PORTS.map((port) => ( -
-
- - {port.workspace} - - +
+
+ {port.workspace}
-
+
{port.ports.map((value) => ( {value} @@ -116,3 +120,53 @@ export function LeftSidebar({ activeDemo }: LeftSidebarProps) {
); } + +function NavRow({ + icon: Icon, + label, + active, + muted, +}: { + icon: typeof LuLayers; + label: string; + active?: boolean; + muted?: boolean; +}) { + return ( +
+ + {label} +
+ ); +} + +function GroupHeader({ + label, + count, + expanded, +}: { + label: string; + count: number; + expanded?: boolean; +}) { + const ChevronIcon = expanded ? LuChevronDown : LuChevronRight; + return ( +
+ + {label} + + {count} + +
+ ); +} diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/MainPanel/MainPanel.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/MainPanel/MainPanel.tsx index 00466806c83..280d90d37b7 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/MainPanel/MainPanel.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/MainPanel/MainPanel.tsx @@ -1,9 +1,8 @@ "use client"; import { motion } from "framer-motion"; -import Image from "next/image"; -import { LuChevronDown, LuPlus, LuTerminal, LuX } from "react-icons/lu"; -import { AGENT_TABS, SETUP_STEPS } from "../../constants"; +import { LuArrowUp } from "react-icons/lu"; +import { SETUP_STEPS } from "../../constants"; import type { ActiveDemo } from "../../types"; import { AsciiSpinner } from "../AsciiSpinner"; @@ -12,90 +11,25 @@ interface MainPanelProps { } export function MainPanel({ activeDemo }: MainPanelProps) { - return ( -
-
-
- {activeDemo === "Create Parallel Branches" ? ( - <> - - setup - - ) : ( - <> - Claude - claude - - )} - -
- - {AGENT_TABS.map((tab) => ( - - {tab.alt} - {tab.label} - - - ))} - -
- - -
-
- -
- - - Terminal - -
- - -
+ const isSetup = activeDemo === "Create Parallel Branches"; -
+ return ( +
+
-
+
{` * ▐▛███▜▌ * * ▝▜█████▛▘ * * ▘▘ ▝▝ *`}
-
+
Claude Code @@ -103,78 +37,73 @@ export function MainPanel({ activeDemo }: MainPanelProps) { v2.0.74
Opus 4.5 · Claude Max
-
+
~/.superset/worktrees/superset/cloud-ws
- {" "} - /mcp + {" "} + /mcp
-
-
+
+
MCP Servers
-
+
1 connected
-
- +
+ 1. - superset-mcp - ✓ connected + superset-mcp + ✓ connected
-
+
config:{" "} - .mcp.json + .mcp.json
-
-
- - - Type a task for Claude... +
+
+ + + Type a task for Claude… -
- ↑ +
+
- {" "} - superset new + {" "} + superset new
-
+
Setting up new parallel environment...
{SETUP_STEPS.map((step) => ( -
+
{step}
))} diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/RightSidebar/RightSidebar.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/RightSidebar/RightSidebar.tsx index 8c6aee480da..034897c2c95 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/RightSidebar/RightSidebar.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/RightSidebar/RightSidebar.tsx @@ -1,7 +1,7 @@ "use client"; import { motion } from "framer-motion"; -import { LuGitPullRequest } from "react-icons/lu"; +import { LuArrowRight, LuGitPullRequest } from "react-icons/lu"; import { FILE_CHANGES } from "../../constants"; import type { ActiveDemo } from "../../types"; import { FileChangeItem } from "../FileChangeItem"; @@ -10,168 +10,200 @@ interface RightSidebarProps { activeDemo: ActiveDemo; } +const TABS = ["Files", "Changes", "Review"] as const; + +const BRANCH_BY_DEMO: Record = { + "Use Any Agents": "use-any-agents", + "Create Parallel Branches": "create-parallel-branches", + "See Changes": "see-changes", + "Open in Any IDE": "open-in-any-ide", +}; + export function RightSidebar({ activeDemo }: RightSidebarProps) { + const isDiff = activeDemo === "See Changes"; + return ( - -
- - Review Changes +
+
+ +
-
-
- Commit message... -
- +
+ {TABS.map((tab) => { + const active = isDiff ? tab === "Changes" : tab === "Files"; + return ( +
+ {tab} + {active && ( + + )} +
+ ); + })} +
+ +
+
+ + + {BRANCH_BY_DEMO[activeDemo]} +
+
+ +1,128 + −98 + · + 10 files + · + + + main + +
+
+
- {FILE_CHANGES.map((file, index) => ( - - ))} +
+ {FILE_CHANGES.map((file, index) => ( + + ))} +
- - -
-
- - - Review PR #827 + +
+ + cloud-workspace.ts + + + + enums.ts + + + +4
- - Open - -
-
- - cloud-workspace.ts - - enums.ts - +4 more -
- -
-
-
@@ -1,4 +1,6 @@
-
- 1 - +
+
+
+ @@ -1,4 +1,6 @@ +
+ import {"{"} db {"}"} from "../db" - -
-
- + - + + import {"{"} CloudWorkspace {"}"} from "./types" - -
-
- + - + + import {"{"} createSSHConnection {"}"} from "./ssh" - -
-
- 2 - -
-
- - - - export const getWorkspaces = () ={">"} {"{"} - -
-
- + - - export const getWorkspaces = async () ={">"} {"{"} - -
-
- 4 - - {" "}return db.query.workspaces - + + + + export const getWorkspaces = () => {"{"} + + + export const getWorkspaces = async () => {"{"} + + {" "}return db.query.workspaces
-
-
- - -
- +
+ + +
+ +
); } + +function DiffLine({ + n, + added, + removed, + children, +}: { + n?: number; + added?: boolean; + removed?: boolean; + children?: React.ReactNode; +}) { + let bg = ""; + let bar = "border-transparent"; + let prefix = ""; + let textColor = "text-muted-foreground/75"; + + if (added) { + bg = "bg-emerald-500/[0.08]"; + bar = "border-emerald-500/85"; + prefix = "+"; + textColor = "text-emerald-300/95"; + } else if (removed) { + bg = "bg-rose-500/[0.08]"; + bar = "border-rose-500/85"; + prefix = "−"; + textColor = "text-rose-300/95"; + } + + return ( +
+ + {prefix || n} + + {children} +
+ ); +} diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/StatusIndicator/StatusIndicator.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/StatusIndicator/StatusIndicator.tsx index cff5bd29562..6bafcc98adb 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/StatusIndicator/StatusIndicator.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/StatusIndicator/StatusIndicator.tsx @@ -10,13 +10,13 @@ const STATUS_STYLES: Record< WorkspaceStatus, { dot: string; ping: string; pulse: boolean } > = { - permission: { ping: "bg-red-400/45", dot: "bg-red-400/80", pulse: true }, + permission: { ping: "bg-amber-300/40", dot: "bg-amber-300/90", pulse: true }, working: { - ping: "bg-orange-500/35", - dot: "bg-orange-500/80", + ping: "bg-brand/40", + dot: "bg-brand", pulse: true, }, - review: { ping: "", dot: "bg-emerald-400/75", pulse: false }, + review: { ping: "", dot: "bg-emerald-400/85", pulse: false }, }; export function StatusIndicator({ status }: StatusIndicatorProps) { diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/TabBar/TabBar.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/TabBar/TabBar.tsx new file mode 100644 index 00000000000..75d0a0e824d --- /dev/null +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/TabBar/TabBar.tsx @@ -0,0 +1,97 @@ +"use client"; + +import { motion } from "framer-motion"; +import Image from "next/image"; +import { + LuChevronDown, + LuExternalLink, + LuPlay, + LuPlus, + LuTerminal, + LuX, +} from "react-icons/lu"; +import { AGENT_TABS } from "../../constants"; +import type { ActiveDemo } from "../../types"; + +interface TabBarProps { + activeDemo: ActiveDemo; +} + +export function TabBar({ activeDemo }: TabBarProps) { + const isSetup = activeDemo === "Create Parallel Branches"; + + return ( +
+
+ {isSetup ? ( + + ) : ( + Claude + )} + {isSetup ? "setup" : "claude"} + + +
+ + {AGENT_TABS.map((tab) => ( + + {tab.alt} + {tab.label} + + + ))} + + + +
+ + +
+
+ ); +} diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/TabBar/index.ts b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/TabBar/index.ts new file mode 100644 index 00000000000..a4038ca4508 --- /dev/null +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/TabBar/index.ts @@ -0,0 +1 @@ +export { TabBar } from "./TabBar"; diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/WindowChrome/WindowChrome.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/WindowChrome/WindowChrome.tsx index b951abd743d..7cbb2f7a025 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/WindowChrome/WindowChrome.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/WindowChrome/WindowChrome.tsx @@ -1,17 +1,58 @@ "use client"; -export function WindowChrome() { +import { LuChevronDown, LuExternalLink, LuX } from "react-icons/lu"; +import type { ActiveDemo } from "../../types"; + +interface WindowChromeProps { + activeDemo?: ActiveDemo; +} + +const TITLE_BY_DEMO: Record = { + "Use Any Agents": { + title: "use any agents in parallel", + branch: "use-any-agents", + }, + "Create Parallel Branches": { + title: "set up parallel branches", + branch: "create-parallel-branches", + }, + "See Changes": { + title: "review cloud-workspace diff", + branch: "see-changes", + }, + "Open in Any IDE": { + title: "edit in any IDE", + branch: "open-in-any-ide", + }, +}; + +export function WindowChrome({ + activeDemo = "Use Any Agents", +}: WindowChromeProps) { + const { title, branch } = TITLE_BY_DEMO[activeDemo]; return ( -
-
-
-
-
+
+
+ + {title} + + + + {branch} + + +
+ +
+
- - superset - -
); } diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/WorkspaceItem/WorkspaceItem.tsx b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/WorkspaceItem/WorkspaceItem.tsx index 996bead5024..37a0b0490b9 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/WorkspaceItem/WorkspaceItem.tsx +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/components/WorkspaceItem/WorkspaceItem.tsx @@ -1,6 +1,7 @@ "use client"; -import { LuFolderGit2, LuGitPullRequest } from "react-icons/lu"; +import { LuGitBranch } from "react-icons/lu"; +import { TbCloud } from "react-icons/tb"; import type { WorkspaceStatus } from "../../types"; import { AsciiSpinner } from "../AsciiSpinner"; import { StatusIndicator } from "../StatusIndicator"; @@ -17,64 +18,56 @@ interface WorkspaceItemProps { export function WorkspaceItem({ name, - branch, add, del, - pr, isActive, status, }: WorkspaceItemProps) { + const isCloud = name === "see changes"; + const isBranch = name === "forward ports"; return (
{isActive && ( -
+ )} -
+ +
{status === "working" ? ( - + + ) : status ? ( + + ) : isCloud ? ( + + ) : isBranch ? ( + ) : ( - - )} - {status && status !== "working" && ( - - - + )}
-
-
- - {name} - - {(add !== undefined || pr) && ( -
- {add !== undefined && ( - - +{add} - {del !== undefined && del > 0 && ( - -{del} - )} - - )} -
- )} -
-
- - {branch} - - {pr && ( - - - {pr} - + + + {name} + + + {add !== undefined && ( + + +{add} + {del !== undefined && del > 0 && ( + −{del} )} -
-
+ + )}
); } diff --git a/apps/marketing/src/app/components/HeroSection/components/AppMockup/constants.ts b/apps/marketing/src/app/components/HeroSection/components/AppMockup/constants.ts index 3ff23f79585..e73278cf9ee 100644 --- a/apps/marketing/src/app/components/HeroSection/components/AppMockup/constants.ts +++ b/apps/marketing/src/app/components/HeroSection/components/AppMockup/constants.ts @@ -43,7 +43,6 @@ export const WORKSPACES: WorkspaceData[] = [ ]; export const FILE_CHANGES: FileChange[] = [ - { path: "bun.lock", add: 38, del: 25, type: "edit" }, { path: "packages/db/src/schema", type: "folder" }, { path: "cloud-workspace.ts", add: 119, del: 0, type: "add", indent: 1 }, { path: "enums.ts", add: 21, del: 0, type: "edit", indent: 1 }, @@ -73,13 +72,26 @@ export const PORTS: PortGroup[] = [ export const AGENT_TABS: AgentTab[] = [ { src: "/app-icons/codex.svg", alt: "Codex", label: "codex", delay: 0.1 }, - { src: "/app-icons/gemini.svg", alt: "Gemini", label: "gemini", delay: 0.25 }, { src: "/app-icons/cursor-agent.svg", alt: "Cursor", label: "cursor", + delay: 0.2, + }, + { + src: "/app-icons/opencode.svg", + alt: "OpenCode", + label: "opencode", + delay: 0.3, + }, + { + src: "/app-icons/copilot-white.svg", + alt: "Copilot", + label: "copilot", delay: 0.4, }, + { src: "/app-icons/amp.svg", alt: "Amp", label: "amp", delay: 0.5 }, + { src: "/app-icons/gemini.svg", alt: "Gemini", label: "gemini", delay: 0.6 }, ]; export const SETUP_STEPS = [