diff --git a/apps/desktop/src/renderer/assets/app-icons/preset-icons/index.ts b/apps/desktop/src/renderer/assets/app-icons/preset-icons/index.ts index 688a210b88d..7705e8d9cb7 100644 --- a/apps/desktop/src/renderer/assets/app-icons/preset-icons/index.ts +++ b/apps/desktop/src/renderer/assets/app-icons/preset-icons/index.ts @@ -1,34 +1,8 @@ +import { getPresetIcon, PRESET_ICONS } from "@superset/ui/icons/preset-icons"; import { useThemeStore } from "renderer/stores/theme/store"; -import claudeIcon from "./claude.svg"; -import codexIcon from "./codex.svg"; -import codexWhiteIcon from "./codex-white.svg"; -import cursorIcon from "./cursor.svg"; -import geminiIcon from "./gemini.svg"; -import opencodeIcon from "./opencode.svg"; -import opencodeWhiteIcon from "./opencode-white.svg"; -interface PresetIconSet { - light: string; - dark: string; -} - -const PRESET_ICONS: Record = { - claude: { light: claudeIcon, dark: claudeIcon }, - codex: { light: codexIcon, dark: codexWhiteIcon }, - gemini: { light: geminiIcon, dark: geminiIcon }, - "cursor-agent": { light: cursorIcon, dark: cursorIcon }, - opencode: { light: opencodeIcon, dark: opencodeWhiteIcon }, -}; - -export function getPresetIcon( - presetName: string, - isDark: boolean, -): string | undefined { - const normalizedName = presetName.toLowerCase().trim(); - const iconSet = PRESET_ICONS[normalizedName]; - if (!iconSet) return undefined; - return isDark ? iconSet.dark : iconSet.light; -} +export { PRESET_ICONS, getPresetIcon }; +export type { PresetIconSet } from "@superset/ui/icons/preset-icons"; export function usePresetIcon(presetName: string): string | undefined { const activeTheme = useThemeStore((state) => state.activeTheme); diff --git a/apps/marketing/public/app-icons/claude.svg b/apps/marketing/public/app-icons/claude.svg new file mode 100644 index 00000000000..62dc0db12da --- /dev/null +++ b/apps/marketing/public/app-icons/claude.svg @@ -0,0 +1 @@ +Claude \ No newline at end of file diff --git a/apps/marketing/public/app-icons/codex.svg b/apps/marketing/public/app-icons/codex.svg new file mode 100644 index 00000000000..97423ea4156 --- /dev/null +++ b/apps/marketing/public/app-icons/codex.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/marketing/public/app-icons/cursor-agent.svg b/apps/marketing/public/app-icons/cursor-agent.svg new file mode 100644 index 00000000000..1f8a7c338a5 --- /dev/null +++ b/apps/marketing/public/app-icons/cursor-agent.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/marketing/public/app-icons/cursor.svg b/apps/marketing/public/app-icons/cursor.svg new file mode 100644 index 00000000000..c074bf27435 --- /dev/null +++ b/apps/marketing/public/app-icons/cursor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/marketing/public/app-icons/finder.png b/apps/marketing/public/app-icons/finder.png new file mode 100644 index 00000000000..2cff579e612 Binary files /dev/null and b/apps/marketing/public/app-icons/finder.png differ diff --git a/apps/marketing/public/app-icons/gemini.svg b/apps/marketing/public/app-icons/gemini.svg new file mode 100644 index 00000000000..f1cf357573d --- /dev/null +++ b/apps/marketing/public/app-icons/gemini.svg @@ -0,0 +1 @@ +Gemini \ No newline at end of file diff --git a/apps/marketing/public/app-icons/iterm.png b/apps/marketing/public/app-icons/iterm.png new file mode 100644 index 00000000000..19cfd018db6 Binary files /dev/null and b/apps/marketing/public/app-icons/iterm.png differ diff --git a/apps/marketing/public/app-icons/jetbrains.svg b/apps/marketing/public/app-icons/jetbrains.svg new file mode 100644 index 00000000000..367c4ffadf4 --- /dev/null +++ b/apps/marketing/public/app-icons/jetbrains.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/apps/marketing/public/app-icons/opencode.svg b/apps/marketing/public/app-icons/opencode.svg new file mode 100644 index 00000000000..b79c7332e20 --- /dev/null +++ b/apps/marketing/public/app-icons/opencode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/marketing/public/app-icons/sublime.svg b/apps/marketing/public/app-icons/sublime.svg new file mode 100644 index 00000000000..e70b24732fe --- /dev/null +++ b/apps/marketing/public/app-icons/sublime.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/marketing/public/app-icons/terminal.png b/apps/marketing/public/app-icons/terminal.png new file mode 100644 index 00000000000..5cd898dd848 Binary files /dev/null and b/apps/marketing/public/app-icons/terminal.png differ diff --git a/apps/marketing/public/app-icons/vscode.svg b/apps/marketing/public/app-icons/vscode.svg new file mode 100644 index 00000000000..0557c2cb3a1 --- /dev/null +++ b/apps/marketing/public/app-icons/vscode.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/marketing/public/app-icons/warp.png b/apps/marketing/public/app-icons/warp.png new file mode 100644 index 00000000000..997c7a152c9 Binary files /dev/null and b/apps/marketing/public/app-icons/warp.png differ diff --git a/apps/marketing/public/app-icons/xcode.svg b/apps/marketing/public/app-icons/xcode.svg new file mode 100644 index 00000000000..cf5ae82e1b3 --- /dev/null +++ b/apps/marketing/public/app-icons/xcode.svg @@ -0,0 +1 @@ + diff --git a/apps/marketing/src/app/components/CTASection/CTASection.tsx b/apps/marketing/src/app/components/CTASection/CTASection.tsx index 4e978b2b683..d03467790c9 100644 --- a/apps/marketing/src/app/components/CTASection/CTASection.tsx +++ b/apps/marketing/src/app/components/CTASection/CTASection.tsx @@ -11,7 +11,7 @@ export function CTASection() { return ( <>
-
+
- Give us a try + Get Superset Today - void; +}) { + return ( +
+ + + {isOpen && ( + +

+ {item.answer} +

+
+ )} +
+
+ ); +} + +export function FAQSection() { + const [openIndex, setOpenIndex] = useState(null); + + const handleToggle = (index: number) => { + setOpenIndex(openIndex === index ? null : index); + }; + + return ( +
+
+
+ {/* Left Column - Title */} + +

+ Frequently +
+ asked questions +

+
+ + {/* Right Column - Accordion */} + +
+ {FAQ_ITEMS.map((item, index) => ( + handleToggle(index)} + /> + ))} +
+
+
+
+
+ ); +} diff --git a/apps/marketing/src/app/components/FAQSection/index.ts b/apps/marketing/src/app/components/FAQSection/index.ts new file mode 100644 index 00000000000..dc66ed4c3e2 --- /dev/null +++ b/apps/marketing/src/app/components/FAQSection/index.ts @@ -0,0 +1 @@ +export { FAQSection } from "./FAQSection"; diff --git a/apps/marketing/src/app/components/FeaturesSection/FeaturesSection.tsx b/apps/marketing/src/app/components/FeaturesSection/FeaturesSection.tsx new file mode 100644 index 00000000000..991ac3fe72e --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/FeaturesSection.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { motion } from "framer-motion"; +import { FeatureDemo } from "./components/FeatureDemo"; +import { IsolationDemo } from "./components/IsolationDemo"; +import { OpenInDemo } from "./components/OpenInDemo"; +import { ParallelExecutionDemo } from "./components/ParallelExecutionDemo"; +import { UniversalCompatibilityDemo } from "./components/UniversalCompatibilityDemo"; +import { FEATURES } from "./constants"; + +const DEMO_COMPONENTS = [ + ParallelExecutionDemo, + UniversalCompatibilityDemo, + IsolationDemo, + OpenInDemo, +]; + +export function FeaturesSection() { + return ( +
+
+ {/* Feature Rows */} +
+ {FEATURES.map((feature, index) => { + const isReversed = index % 2 === 1; + const DemoComponent = DEMO_COMPONENTS[index]; + return ( + + {/* Text Content */} +
+
+ + {feature.tag} + +

+ {feature.title} +

+
+

+ {feature.description} +

+
+ + {/* Demo */} +
+ + {DemoComponent && } + +
+
+ ); + })} +
+
+
+ ); +} diff --git a/apps/marketing/src/app/components/FeaturesSection/components/FeatureDemo/FeatureDemo.tsx b/apps/marketing/src/app/components/FeaturesSection/components/FeatureDemo/FeatureDemo.tsx new file mode 100644 index 00000000000..aa65c25a074 --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/FeatureDemo/FeatureDemo.tsx @@ -0,0 +1,33 @@ +"use client"; + +import { MeshGradient } from "@superset/ui/mesh-gradient"; +import type { ReactNode } from "react"; + +interface FeatureDemoProps { + children: ReactNode; + colors: readonly [string, string, string, string]; + className?: string; +} + +export function FeatureDemo({ + children, + colors, + className = "", +}: FeatureDemoProps) { + return ( +
+ {/* Background gradient */} + + + {/* Content overlay */} +
+ {children} +
+
+ ); +} diff --git a/apps/marketing/src/app/components/FeaturesSection/components/FeatureDemo/index.ts b/apps/marketing/src/app/components/FeaturesSection/components/FeatureDemo/index.ts new file mode 100644 index 00000000000..c0923288e2a --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/FeatureDemo/index.ts @@ -0,0 +1 @@ +export { FeatureDemo } from "./FeatureDemo"; diff --git a/apps/marketing/src/app/components/FeaturesSection/components/IsolationDemo/IsolationDemo.tsx b/apps/marketing/src/app/components/FeaturesSection/components/IsolationDemo/IsolationDemo.tsx new file mode 100644 index 00000000000..5e5d5ee910e --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/IsolationDemo/IsolationDemo.tsx @@ -0,0 +1,258 @@ +"use client"; + +import { motion, useInView } from "framer-motion"; +import { useRef } from "react"; +import { + HiOutlineChatBubbleLeftRight, + HiOutlineCheck, + HiOutlineDocumentText, +} from "react-icons/hi2"; +import { VscGitCommit, VscGitPullRequest } from "react-icons/vsc"; + +const SIDEBAR_FILES = [ + { name: "HeroSection.tsx", added: 12, removed: 3 }, + { name: "GridBackground.ts", added: 45, removed: 0 }, + { name: "constants.ts", added: 8, removed: 2 }, + { name: "ProductDemo.tsx", added: 23, removed: 15 }, +]; + +const DIFF_LINES = [ + { id: "line-1", type: "context", content: "export function HeroSection() {" }, + { id: "line-2", type: "context", content: "\u00A0\u00A0return (" }, + { + id: "line-3", + type: "removed", + content: '\u00A0\u00A0\u00A0\u00A0
', + }, + { + id: "line-4", + type: "added", + content: '\u00A0\u00A0\u00A0\u00A0
', + }, + { + id: "line-5", + type: "added", + content: "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0", + }, + { + id: "line-6", + type: "context", + content: + '\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0
', + }, + { + id: "line-7", + type: "removed", + content: "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0

Welcome

", + }, + { + id: "line-8", + type: "added", + content: "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0", + }, + { + id: "line-12", + type: "added", + content: + "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0Superset", + }, + { + id: "line-13", + type: "added", + content: "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0", + }, + { + id: "line-14", + type: "context", + content: "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0
", + }, + { id: "line-15", type: "removed", content: "\u00A0\u00A0\u00A0\u00A0
" }, + { + id: "line-16", + type: "added", + content: "\u00A0\u00A0\u00A0\u00A0
", + }, + { id: "line-17", type: "context", content: "\u00A0\u00A0);" }, + { id: "line-18", type: "context", content: "}" }, +]; + +export function IsolationDemo() { + const ref = useRef(null); + const isInView = useInView(ref, { once: true, margin: "-100px" }); + + return ( + + {/* Header */} +
+
+
+
+
+
+
+ + components/HeroSection/HeroSection.tsx + +
+
+ + +
+
+ +
+ {/* Sidebar */} +
+ {/* Sidebar sections */} +
+
+ + Messages +
+
+ + Commits + + 3 + +
+
+ + Against Main + +
+
+ + {/* Files */} +
+
+ Unstaged +
+ {SIDEBAR_FILES.map((file, index) => ( + + + + {file.name} + + + +{file.added} + + {file.removed > 0 && ( + + -{file.removed} + + )} + + ))} +
+
+ + {/* Diff content */} +
+
+ {DIFF_LINES.map((line, index) => ( + + + {index + 1} + + + {line.type === "added" + ? "+" + : line.type === "removed" + ? "-" + : " "} + + + {line.content} + + + ))} +
+
+
+ + ); +} diff --git a/apps/marketing/src/app/components/FeaturesSection/components/IsolationDemo/index.ts b/apps/marketing/src/app/components/FeaturesSection/components/IsolationDemo/index.ts new file mode 100644 index 00000000000..4199c46f5bd --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/IsolationDemo/index.ts @@ -0,0 +1 @@ +export { IsolationDemo } from "./IsolationDemo"; diff --git a/apps/marketing/src/app/components/FeaturesSection/components/OpenInDemo/OpenInDemo.tsx b/apps/marketing/src/app/components/FeaturesSection/components/OpenInDemo/OpenInDemo.tsx new file mode 100644 index 00000000000..43b71b1f27a --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/OpenInDemo/OpenInDemo.tsx @@ -0,0 +1,178 @@ +"use client"; + +import { motion, useInView } from "framer-motion"; +import Image from "next/image"; +import { useRef } from "react"; +import { + HiChevronDown, + HiChevronRight, + HiMagnifyingGlass, + HiOutlineDocument, + HiOutlineFolder, +} from "react-icons/hi2"; + +const IDE_OPTIONS = [ + { id: "finder", label: "Finder", icon: "/app-icons/finder.png" }, + { + id: "cursor", + label: "Cursor", + icon: "/app-icons/cursor.svg", + shortcut: "⌘O", + }, + { id: "vscode", label: "VS Code", icon: "/app-icons/vscode.svg" }, + { id: "xcode", label: "Xcode", icon: "/app-icons/xcode.svg" }, + { id: "sublime", label: "Sublime Text", icon: "/app-icons/sublime.svg" }, + { id: "terminal", label: "Terminal", icon: "/app-icons/terminal.png" }, + { id: "jetbrains", label: "JetBrains", icon: "/app-icons/jetbrains.svg" }, +]; + +const FILE_TREE = [ + { type: "folder", name: "components", expanded: true }, + { type: "file", name: "HeroSection.tsx", indent: 1, selected: true }, + { type: "file", name: "constants.ts", indent: 1 }, + { type: "file", name: "index.ts", indent: 1 }, + { type: "folder", name: "hooks", expanded: false }, + { type: "folder", name: "utils", expanded: false }, +]; + +export function OpenInDemo() { + const ref = useRef(null); + const isInView = useInView(ref, { once: true, margin: "-100px" }); + + return ( + + {/* Window */} +
+ {/* Header */} +
+
+
+
+
+
+
+ + superset + +
+
+ + src +
+
+ + {/* Toolbar row */} +
+ {/* Search input */} +
+ + Search files... +
+ + {/* Open in button */} + + + + +
+ + {/* File tree */} +
+ {FILE_TREE.map((item, index) => ( + + {item.type === "folder" ? ( + <> + + + + ) : ( + <> + + + + )} + {item.name} + + ))} +
+
+ + {/* Dropdown Menu - positioned outside window for overflow effect */} + + {IDE_OPTIONS.map((ide, index) => ( + +
+
+ {ide.label} +
+ {ide.label} +
+ {ide.shortcut && ( + {ide.shortcut} + )} +
+ ))} +
+ + ); +} diff --git a/apps/marketing/src/app/components/FeaturesSection/components/OpenInDemo/index.ts b/apps/marketing/src/app/components/FeaturesSection/components/OpenInDemo/index.ts new file mode 100644 index 00000000000..ad6069c4a0a --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/OpenInDemo/index.ts @@ -0,0 +1 @@ +export { OpenInDemo } from "./OpenInDemo"; diff --git a/apps/marketing/src/app/components/FeaturesSection/components/ParallelExecutionDemo/ParallelExecutionDemo.tsx b/apps/marketing/src/app/components/FeaturesSection/components/ParallelExecutionDemo/ParallelExecutionDemo.tsx new file mode 100644 index 00000000000..cc8991de5d6 --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/ParallelExecutionDemo/ParallelExecutionDemo.tsx @@ -0,0 +1,276 @@ +"use client"; + +import { motion, useInView } from "framer-motion"; +import { useEffect, useRef, useState } from "react"; +import { HiCheck } from "react-icons/hi2"; + +const IN_PROGRESS_TASKS = [ + { + id: "task-1", + name: "Analyze Tab vs Agent Usag...", + status: "Generating", + rotation: 45, + }, + { + id: "task-2", + name: "PyTorch MNIST Experiments", + status: "Generating", + rotation: 180, + }, + { + id: "task-3", + name: "Fix PR Comments Fetching I...", + status: "Generating", + rotation: 270, + }, +]; + +const READY_FOR_REVIEW = [ + { + id: "review-1", + name: "Enterprise Order Mana...", + time: "now", + added: 93, + removed: 18, + summary: "Perfect! I've implem...", + }, + { + id: "review-2", + name: "Set up Cursor Rules fo...", + time: "30m", + added: 37, + removed: 0, + summary: "Set up Cursor Rules f...", + }, + { + id: "review-3", + name: "Bioinformatics Tools", + time: "45m", + added: 135, + removed: 21, + summary: "Bioinformatics Tools", + }, +]; + +const TERMINAL_LINES = [ + "$ claude", + "\u00A0", + "╭──────────────────────────╮", + "│\u00A0\u00A0Claude Code\u00A0\u00A0\u00A0\u00A0v1.0.42\u00A0\u00A0│", + "╰──────────────────────────╯", + "\u00A0", + "> Implement order validation", + "\u00A0", + "I'll implement order validation.", + "Let me examine the existing schema...", + "\u00A0", + "Read: src/schemas/order.ts", + "Read: src/api/orders/validate.ts", + "\u00A0", + "✓ Added validation for required fields,", + "\u00A0\u00A0quantity checks, and price formats.", +]; + +function SpinnerIcon({ + className, + rotation = 0, +}: { + className?: string; + rotation?: number; +}) { + return ( + + ); +} + +export function ParallelExecutionDemo() { + const ref = useRef(null); + const isInView = useInView(ref, { once: true, margin: "-100px" }); + const [displayedLines, setDisplayedLines] = useState([]); + const [showCursor, setShowCursor] = useState(true); + + // Line-by-line animation + useEffect(() => { + if (!isInView) return; + + let lineIndex = 0; + const interval = setInterval(() => { + if (lineIndex < TERMINAL_LINES.length) { + setDisplayedLines(TERMINAL_LINES.slice(0, lineIndex + 1)); + lineIndex++; + } else { + clearInterval(interval); + } + }, 150); + + return () => clearInterval(interval); + }, [isInView]); + + // Blinking cursor + useEffect(() => { + const interval = setInterval(() => { + setShowCursor((prev) => !prev); + }, 530); + return () => clearInterval(interval); + }, []); + + return ( + + {/* Window chrome */} +
+
+
+
+
+
+ Superset +
+ +
+ {/* Sidebar */} +
+ {/* In Progress Section */} +
+
+ In Progress{" "} + {IN_PROGRESS_TASKS.length} +
+ {IN_PROGRESS_TASKS.map((task, index) => ( + + +
+
+ {task.name} +
+
{task.status}
+
+
+ ))} +
+ + {/* Ready for Review Section */} +
+
+ Ready for Review{" "} + {READY_FOR_REVIEW.length} +
+ {READY_FOR_REVIEW.map((task, index) => ( + + +
+
+ + {task.name} + + + {task.time} + +
+
+ +{task.added} + {task.removed > 0 && ( + -{task.removed} + )} + + · {task.summary} + +
+
+
+ ))} +
+
+ + {/* Terminal Area */} +
+ {/* Terminal content */} +
+ {displayedLines.map((line, index) => ( +
") ? "text-green-400" : ""} ${line.startsWith("Read:") ? "text-blue-400" : ""} ${line.startsWith("✓") ? "text-green-400" : ""}`} + > + {line || "\u00A0"} +
+ ))} + {displayedLines.length === TERMINAL_LINES.length && ( + + )} +
+ + {/* Input box */} +
+
+ {">"} + + Type a message... + +
+
+ +
+
+ +
+
+
+
+
+
+ + ); +} diff --git a/apps/marketing/src/app/components/FeaturesSection/components/ParallelExecutionDemo/index.ts b/apps/marketing/src/app/components/FeaturesSection/components/ParallelExecutionDemo/index.ts new file mode 100644 index 00000000000..8e392bad894 --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/ParallelExecutionDemo/index.ts @@ -0,0 +1 @@ +export { ParallelExecutionDemo } from "./ParallelExecutionDemo"; diff --git a/apps/marketing/src/app/components/FeaturesSection/components/UniversalCompatibilityDemo/UniversalCompatibilityDemo.tsx b/apps/marketing/src/app/components/FeaturesSection/components/UniversalCompatibilityDemo/UniversalCompatibilityDemo.tsx new file mode 100644 index 00000000000..ad0742f6373 --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/UniversalCompatibilityDemo/UniversalCompatibilityDemo.tsx @@ -0,0 +1,90 @@ +"use client"; + +import { motion, useInView } from "framer-motion"; +import Image from "next/image"; +import { useRef } from "react"; +import { HiOutlineTerminal } from "react-icons/hi"; +import { HiOutlineCodeBracket, HiPlus } from "react-icons/hi2"; + +const AGENTS = [ + { name: "Claude", icon: "/app-icons/claude.svg", size: 18 }, + { name: "OpenCode", icon: "/app-icons/opencode.svg", size: 14 }, + { name: "Codex", icon: "/app-icons/codex.svg", size: 18 }, + { name: "Gemini", icon: "/app-icons/gemini.svg", size: 18 }, + { name: "Cursor Agent", icon: "/app-icons/cursor-agent.svg", size: 18 }, +]; + +export function UniversalCompatibilityDemo() { + const ref = useRef(null); + const isInView = useInView(ref, { once: true, margin: "-100px" }); + + return ( + + {/* Header */} +
+
+
+
+
+
+
+ + superset + +
+
+ + main +
+
+ + {/* New Terminal button */} +
+
+ + New Terminal + ... + +
+
+ + {/* Agent list */} +
+ {AGENTS.map((agent, index) => ( + +
+ {agent.name} +
+ {agent.name} +
+ ))} +
+ + {/* Terminal count */} +
+
+ + Terminals (3) +
+
+ + ); +} diff --git a/apps/marketing/src/app/components/FeaturesSection/components/UniversalCompatibilityDemo/index.ts b/apps/marketing/src/app/components/FeaturesSection/components/UniversalCompatibilityDemo/index.ts new file mode 100644 index 00000000000..1c4de1cbf4e --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/components/UniversalCompatibilityDemo/index.ts @@ -0,0 +1 @@ +export { UniversalCompatibilityDemo } from "./UniversalCompatibilityDemo"; diff --git a/apps/marketing/src/app/components/FeaturesSection/constants.ts b/apps/marketing/src/app/components/FeaturesSection/constants.ts new file mode 100644 index 00000000000..d6def73c52c --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/constants.ts @@ -0,0 +1,37 @@ +export interface Feature { + tag: string; + title: string; + description: string; + colors: readonly [string, string, string, string]; +} + +export const FEATURES: Feature[] = [ + { + tag: "Parallel Execution", + title: "Run dozens of agents at once", + description: + "Launch multiple AI coding agents across different tasks. Work on features, fix bugs, and refactor code — all in parallel.", + colors: ["#7f1d1d", "#991b1b", "#450a0a", "#1a1a2e"], + }, + { + tag: "Universal Compatibility", + title: "Works with any CLI agent", + description: + "Superset is agent-agnostic. Use Claude Code, OpenCode, Cursor, or any CLI-based coding tool. Switch between agents seamlessly.", + colors: ["#047857", "#065f46", "#064e3b", "#1a1a2e"], + }, + { + tag: "Isolation", + title: "Changes are isolated", + description: + "Each agent runs in its own isolated Git worktree. No merge conflicts, no stepping on each other's changes. Review and merge work when you're ready.", + colors: ["#1e40af", "#1e3a8a", "#172554", "#1a1a2e"], + }, + { + tag: "Open Anywhere", + title: "Open in any IDE", + description: + "Jump into your favorite editor with one click. VS Code, Cursor, Xcode, JetBrains IDEs, or any terminal — open worktrees exactly where you need them.", + colors: ["#7c3aed", "#6d28d9", "#4c1d95", "#1a1a2e"], + }, +]; diff --git a/apps/marketing/src/app/components/FeaturesSection/index.ts b/apps/marketing/src/app/components/FeaturesSection/index.ts new file mode 100644 index 00000000000..561353fb3de --- /dev/null +++ b/apps/marketing/src/app/components/FeaturesSection/index.ts @@ -0,0 +1 @@ +export { FeaturesSection } from "./FeaturesSection"; diff --git a/apps/marketing/src/app/components/HeroSection/HeroSection.tsx b/apps/marketing/src/app/components/HeroSection/HeroSection.tsx index d4821c3801d..6de8a1010b0 100644 --- a/apps/marketing/src/app/components/HeroSection/HeroSection.tsx +++ b/apps/marketing/src/app/components/HeroSection/HeroSection.tsx @@ -19,7 +19,7 @@ export function HeroSection() {
-
+
+
{/* Animated mesh gradient backgrounds - all rendered, opacity controlled */} {DEMO_OPTIONS.map((option) => ( -
+
{/* Heading */} - - + {/* Left fade overlay */} +
+ +
{CLIENT_LOGOS.map((client) => (
+ + {/* Right fade overlay */} +
diff --git a/apps/marketing/src/app/components/VideoSection/VideoSection.tsx b/apps/marketing/src/app/components/VideoSection/VideoSection.tsx index 0f03ebac55e..a02ced4d653 100644 --- a/apps/marketing/src/app/components/VideoSection/VideoSection.tsx +++ b/apps/marketing/src/app/components/VideoSection/VideoSection.tsx @@ -4,9 +4,8 @@ import { motion } from "framer-motion"; export function VideoSection() { return ( -
-
- {/* Heading */} +
+
-
-

- A Superset of your favorite tools +
+

+ Code 10x faster with no switching cost

-

- Get all the best AI coding tools in one place. We want to support - and stay compatible with whatever CLI agents you already use. +

+ Superset works with your existing tools. We provides + parallelization and better UX to enhance your Claude Code, + OpenCode, Cursor, etc.

- {/* Video Demo Area */} -
+