From 494f891783697813a7a9c2a8134c61d1f1758a24 Mon Sep 17 00:00:00 2001 From: Shivam Kumar Date: Tue, 11 Aug 2026 13:02:07 +0530 Subject: [PATCH] feat(landing): Quick Setup accordion, favicon, hide Slack bot section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Quick Setup: replace the tabbed/collapsed-hero layout with a single accordion card (Interactive install, Codex config, Windsurf). One group open at a time, first one open by default, all collapsible. Cloud/Self-hosted mode toggle sits above the card. - Add the official Parseable favicon (SVG, from @thesvg/cli) and wire it up in index.html. - Comment out the Slack bot section on the landing page until the bot itself is published — code stays in place, easy one-line re-enable. Co-Authored-By: Claude Sonnet 5 --- src/ui-app/components/landing/QuickSetup.tsx | 263 ++++++++++--------- src/ui-app/index.html | 1 + src/ui-app/pages/LandingPage.tsx | 6 +- src/ui-app/public/favicon.svg | 8 + 4 files changed, 147 insertions(+), 131 deletions(-) create mode 100644 src/ui-app/public/favicon.svg diff --git a/src/ui-app/components/landing/QuickSetup.tsx b/src/ui-app/components/landing/QuickSetup.tsx index 02a828e..c3a4b99 100644 --- a/src/ui-app/components/landing/QuickSetup.tsx +++ b/src/ui-app/components/landing/QuickSetup.tsx @@ -1,6 +1,12 @@ import { useCallback, useState } from "react"; import type { ReactNode } from "react"; -import { IconCheck, IconCloud, IconCopy, IconServer } from "@tabler/icons-react"; +import { + IconCheck, + IconChevronDown, + IconCloud, + IconCopy, + IconServer, +} from "@tabler/icons-react"; type CopyKey = string; @@ -98,11 +104,30 @@ const CLIENTS = [ type Client = (typeof CLIENTS)[number]; type ParseableMode = "cloud" | "self-hosted"; +type ClientGroup = { + id: "init" | "codex" | "windsurf"; + clients: Client[]; +}; + +const GROUPS: ClientGroup[] = [ + { + id: "init", + clients: ["Claude Code", "Cursor", "VS Code", "Claude Desktop"], + }, + { + id: "codex", + clients: ["ChatGPT Desktop", "Codex"], + }, + { + id: "windsurf", + clients: ["Windsurf"], + }, +]; + const HOSTED_URL = `${window.location.origin}/mcp`; const PARSEABLE_URL = "https://your-parseable.example.com"; const API_KEY = "your-parseable-api-key"; const INSTALL_COMMAND = "npx -y @parseable/parseable-mcp-server@latest init"; -const INIT_CLIENTS = new Set(["Claude Code", "Cursor", "VS Code", "Claude Desktop"]); function authHeaders(mode: ParseableMode) { return mode === "cloud" ? { "X-Parseable-Mode": "cloud", "X-API-Key": API_KEY } @@ -204,70 +229,41 @@ http_headers = { ${Object.entries(headers) }; } -function SectionDivider() { - return ( -
- ); -} - function DarkCodeBlock({ content, copyKey, copied, onCopy, - label, }: { content: string; copyKey: string; copied: string | null; onCopy: (text: string, key: string) => void; - label?: string; }) { return (
- {label && ( -
- - {label} - - -
- )} +
{children}

; +function ClientRow({ clients }: { clients: Client[] }) { + return ( +
+ {clients.map((client) => ( +
+ + {CLIENT_ICONS[client]} + + {client} +
+ ))} +
+ ); +} + +function ModeToggle({ + mode, + onChange, + compact = false, +}: { + mode: ParseableMode; + onChange: (mode: ParseableMode) => void; + compact?: boolean; +}) { + return ( +
+ {(["cloud", "self-hosted"] as const).map((option) => ( + + ))} +
+ ); } export function QuickSetup() { - const [active, setActive] = useState("Cursor"); const [mode, setMode] = useState("cloud"); + const [openGroup, setOpenGroup] = useState( + GROUPS[0].id, + ); const { copied, copy } = useCopy(); - const manual = manualConfig(mode)[active]; + const configs = manualConfig(mode); return (
- {/* Mode toggle — shared across every client tab below */} + {/* Mode toggle — shared across every block below */}
-
- {(["cloud", "self-hosted"] as const).map((option) => ( - - ))} -
+
-
- {/* Tabs */} -
-
- {CLIENTS.map((client) => ( + {/* Accordion — one group open at a time, first one open by default */} +
+ {GROUPS.map((group) => { + const isInit = group.id === "init"; + const isOpen = openGroup === group.id; + const manual = configs[group.clients[0]]; + return ( +
- ))} -
-
- - {/* Tab content */} -
-

- {INIT_CLIENTS.has(active) - ? `Run interactive setup, select ${active}, then choose Parseable Cloud or Self-hosted. The installer writes the configuration for you.` - : "This client is not supported by interactive setup yet. Add the configuration manually."} -

- {INIT_CLIENTS.has(active) && ( -
- Install and configure - -
- )} - {!INIT_CLIENTS.has(active) && ( -
- Manual configuration · {manual.file} - + {isOpen && ( +
+ +
+ )}
- )} -
+ ); + })}
diff --git a/src/ui-app/index.html b/src/ui-app/index.html index 1aef985..88d065f 100644 --- a/src/ui-app/index.html +++ b/src/ui-app/index.html @@ -4,6 +4,7 @@ + Parseable MCP Server diff --git a/src/ui-app/pages/LandingPage.tsx b/src/ui-app/pages/LandingPage.tsx index 9d78421..65267fa 100644 --- a/src/ui-app/pages/LandingPage.tsx +++ b/src/ui-app/pages/LandingPage.tsx @@ -5,7 +5,7 @@ import { Hero } from "../components/landing/Hero"; import { Nav } from "../components/landing/Nav"; import { Prompts } from "../components/landing/Prompts"; import { QuickSetup } from "../components/landing/QuickSetup"; -import { SlackBot } from "../components/landing/SlackBot"; +// import { SlackBot } from "../components/landing/SlackBot"; import { TwoWays } from "../components/landing/TwoWays"; export function LandingPage() { @@ -17,7 +17,9 @@ export function LandingPage() {
- + {/* Slack bot isn't published yet — re-enable by uncommenting the + import above and this line once it's live. */} + {/* */} diff --git a/src/ui-app/public/favicon.svg b/src/ui-app/public/favicon.svg new file mode 100644 index 0000000..9f8c3d7 --- /dev/null +++ b/src/ui-app/public/favicon.svg @@ -0,0 +1,8 @@ + + + + + + + +