diff --git a/ee/apps/landing/components/landing-enterprise-hero.tsx b/ee/apps/landing/components/landing-enterprise-hero.tsx new file mode 100644 index 00000000..004e1607 --- /dev/null +++ b/ee/apps/landing/components/landing-enterprise-hero.tsx @@ -0,0 +1,842 @@ +"use client"; + +import { + Bell, + Brain, + ChevronRight, + DollarSign, + Gauge, + Search, + Users +} from "lucide-react"; +import { useState } from "react"; +import { OpenWorkMark } from "./openwork-mark"; + +type Department = { + name: string; + dailyActive: string; + spend: string; + avgPerPerson: string; + /** Daily active users over the last 10 weekdays. */ + trend: number[]; + powerUsers: string[]; +}; + +type ToolRow = { + tool: string; + penetration: string; + topDepartment: string; + topUsers: string[]; + featured?: boolean; +}; + +type PowerUser = { + name: string; + initials: string; + department: string; + topTool: string; + /** Cumulative requests by weekday (10 weekdays). Shape reveals usage personality. */ + trend: number[]; + /** One-line descriptor of the usage personality (shown as tooltip). */ + trendNote: string; + requests: string; + inputTokens: string; + outputTokens: string; + cost: string; +}; + +const departments: Department[] = [ + { + name: "Engineering", + dailyActive: "48 / 82", + spend: "$330K", + avgPerPerson: "$4.1K", + trend: [42, 44, 43, 45, 46, 46, 47, 47, 48, 48], + powerUsers: ["JC", "LT", "AL", "+5"] + }, + { + name: "Product", + dailyActive: "9 / 24", + spend: "$90K", + avgPerPerson: "$3.8K", + trend: [4, 5, 5, 4, 6, 7, 6, 8, 8, 9], + powerUsers: ["HL", "DG", "AR", "+1"] + }, + { + name: "Customer Support", + dailyActive: "7 / 36", + spend: "$30K", + avgPerPerson: "$968", + trend: [3, 4, 4, 5, 5, 6, 6, 7, 7, 7], + powerUsers: ["MF", "SG", "RM", "+2"] + }, + { + name: "Marketing", + dailyActive: "3 / 28", + spend: "$18K", + avgPerPerson: "$643", + trend: [1, 1, 1, 2, 1, 2, 2, 3, 3, 3], + powerUsers: ["RF", "AS", "JR", "+1"] + }, + { + name: "Sales", + dailyActive: "1 / 25", + spend: "$15K", + avgPerPerson: "$600", + trend: [0, 1, 0, 0, 0, 1, 1, 0, 1, 1], + powerUsers: ["AC", "WB", "HF", "+2"] + }, + { + name: "Legal", + dailyActive: "0 / 12", + spend: "$7K", + avgPerPerson: "$583", + trend: [3, 2, 2, 1, 1, 1, 0, 0, 0, 0], + powerUsers: ["SD", "OB", "RH", "+1"] + } +]; + +const toolRows: ToolRow[] = [ + { + tool: "OpenWork", + penetration: "41%", + topDepartment: "Customer Support", + topUsers: ["AL", "AC", "WB"], + featured: true + }, + { + tool: "Cursor", + penetration: "24%", + topDepartment: "Engineering", + topUsers: ["JC", "LT", "AT"] + }, + { + tool: "Figma AI", + penetration: "11%", + topDepartment: "Product", + topUsers: ["HL", "RF"] + }, + { + tool: "Notion AI", + penetration: "9%", + topDepartment: "Product", + topUsers: ["DG", "AS"] + }, + { + tool: "Zendesk AI", + penetration: "7%", + topDepartment: "Customer Support", + topUsers: ["MF", "SG"] + } +]; + +const powerUsers: PowerUser[] = [ + { + name: "John Carmack", + initials: "JC", + department: "Engineering", + topTool: "Zed", + trend: [60, 200, 290, 490, 610, 780, 860, 1080, 1260, 1400], + trendNote: "Deep-work bursts, quiet days in between", + requests: "1.4K", + inputTokens: "820K", + outputTokens: "310K", + cost: "$1.2K" + }, + { + name: "Linus Torvalds", + initials: "LT", + department: "Engineering", + topTool: "Omarchy", + trend: [105, 217, 325, 440, 550, 658, 771, 881, 993, 1100], + trendNote: "Steady daily rhythm, every weekday the same", + requests: "1.1K", + inputTokens: "640K", + outputTokens: "250K", + cost: "$910" + }, + { + name: "Ada Lovelace", + initials: "AL", + department: "Engineering", + topTool: "Hugging Face", + trend: [160, 300, 420, 530, 630, 720, 800, 860, 920, 960], + trendNote: "Early-adopter curve — curiosity cooling off", + requests: "960", + inputTokens: "540K", + outputTokens: "210K", + cost: "$780" + }, + { + name: "Alan Turing", + initials: "AT", + department: "Engineering", + topTool: "Claude Code", + trend: [88, 176, 264, 352, 440, 528, 616, 704, 792, 880], + trendNote: "Scheduled automation — same batch every day", + requests: "880", + inputTokens: "500K", + outputTokens: "200K", + cost: "$690" + }, + { + name: "Marie Curie", + initials: "MC", + department: "Engineering", + topTool: "OpenWork", + trend: [30, 70, 120, 180, 250, 330, 420, 520, 615, 680], + trendNote: "Learning curve — compounding every week", + requests: "680", + inputTokens: "380K", + outputTokens: "170K", + cost: "$520" + }, + { + name: "Andrew Carnegie", + initials: "AC", + department: "Sales", + topTool: "OpenWork", + trend: [15, 35, 60, 90, 130, 190, 265, 345, 430, 510], + trendNote: "Late adopter — just caught the wave", + requests: "510", + inputTokens: "290K", + outputTokens: "140K", + cost: "$420" + }, + { + name: "Warren Buffett", + initials: "WB", + department: "Sales", + topTool: "OpenWork", + trend: [40, 82, 125, 168, 210, 253, 297, 341, 386, 430], + trendNote: "Patient, near-identical daily habit", + requests: "430", + inputTokens: "240K", + outputTokens: "115K", + cost: "$360" + } +]; + +const peopleByInitials: Record< + string, + { name?: string; department: string } +> = { + JC: { name: "John Carmack", department: "Engineering" }, + LT: { name: "Linus Torvalds", department: "Engineering" }, + AL: { name: "Ada Lovelace", department: "Engineering" }, + MC: { name: "Marie Curie", department: "Engineering" }, + AT: { name: "Alan Turing", department: "Engineering" }, + AC: { name: "Andrew Carnegie", department: "Sales" }, + WB: { name: "Warren Buffett", department: "Sales" }, + HF: { name: "Henry Ford", department: "Sales" }, + HL: { department: "Product" }, + DG: { department: "Product" }, + AR: { department: "Product" }, + MF: { department: "Customer Support" }, + SG: { department: "Customer Support" }, + RM: { department: "Customer Support" }, + RF: { department: "Marketing" }, + AS: { department: "Marketing" }, + JR: { department: "Marketing" }, + SD: { department: "Legal" }, + OB: { department: "Legal" }, + RH: { department: "Legal" } +}; + +type TabId = "departments" | "users" | "tools"; + +type Props = { + /** When true, the outer card renders its own rounded border + shadow. When false, the caller wraps it. */ + standalone?: boolean; +}; + +export function LandingEnterpriseHero({ standalone = false }: Props) { + const [activeTab, setActiveTab] = useState("departments"); + + const shell = standalone + ? "overflow-hidden rounded-[28px] border border-[#dde2ea] bg-[#fbfbfa] shadow-[0_18px_60px_rgba(7,25,44,0.08)]" + : "overflow-hidden bg-[#fbfbfa]"; + + const tabCopy: Record = { + departments: { + crumb: "Departments", + description: + "Where AI usage is concentrated across the org, by team." + }, + users: { + crumb: "Power users", + description: + "The individuals driving the most AI usage. Use them to teach the rest of the org." + }, + tools: { + crumb: "AI tools", + description: + "The tools people reach for, who uses them most, and who to ask for access." + } + }; + + return ( +
+ + +
+
+ + + +

+ {tabCopy[activeTab].description} +

+ +
+ } + title="Daily active AI users" + value="68 / 131" + tone="violet" + /> + } + title="Monthly spend" + value="$480K" + tone="green" + /> + } + title="Top-tool penetration" + value="41%" + subvalue="OpenWork · 54 users" + tone="blue" + /> +
+ +
+ +
+ +
+ {activeTab === "departments" ? : null} + {activeTab === "users" ? : null} + {activeTab === "tools" ? : null} +
+
+
+ ); +} + +function MacChrome() { + return ( +
+
+
+
+
+ ); +} + +function HeaderBar({ crumb }: { crumb: string }) { + return ( +
+
+ + + Q2 + + + AI Adoption + + + + {crumb} + +
+ +
+ + +
+ AG +
+
+
+ ); +} + +type StatCardProps = { + icon: React.ReactNode; + title: string; + value: string; + subvalue?: string; + tone: "violet" | "green" | "blue"; +}; + +function StatCard({ icon, title, value, subvalue, tone }: StatCardProps) { + return ( +
+
+
+ {icon} +
+ +
+
+ {title} +
+
+ {value} +
+ {subvalue ? ( +
+ {subvalue} +
+ ) : null} +
+
+
+ ); +} + +type TabBarProps = { + activeTab: TabId; + onChange: (tab: TabId) => void; +}; + +function TabBar({ activeTab, onChange }: TabBarProps) { + const tabs: Array<{ id: TabId; label: string }> = [ + { id: "departments", label: "Departments" }, + { id: "users", label: "Power users" }, + { id: "tools", label: "AI tools" } + ]; + + return ( +
+ {tabs.map((tab) => { + const selected = tab.id === activeTab; + return ( + + ); + })} +
+ ); +} + +function DepartmentsTable() { + return ( +
+
+
Team
+
Daily active
+
Spend
+
Avg / person
+
Adoption trend
+
Power users
+
+ + {departments.map((row) => ( +
+
+ {row.name} +
+
+ {row.dailyActive} +
+
+ {row.spend} +
+
+ {row.avgPerPerson} +
+
+ +
+
+ {row.powerUsers.map((user) => + user.startsWith("+") ? ( + + {user} + + ) : ( + + ) + )} +
+
+ ))} +
+ ); +} + +function PowerUsersTable() { + return ( +
+
+
Name
+
Top tool
+
Cumulative trend
+
Requests
+
In tokens
+
Out tokens
+
Cost
+
+ + {powerUsers.map((user) => ( +
+
+ +
+
+ {user.name} +
+
+ {user.department} +
+
+
+ +
+ + + {user.topTool} + +
+ +
+ +
+ +
+ {user.requests} +
+
+ {user.inputTokens} +
+
+ {user.outputTokens} +
+
+ {user.cost} +
+
+ ))} +
+ ); +} + +function ToolsTable() { + return ( +
+
+
Tool
+
Penetration
+
Top department
+
Power users
+
+ + {toolRows.map((row) => ( +
+
+ + + {row.tool} + +
+
+ {row.penetration} +
+
+ {row.topDepartment} +
+
+ {row.topUsers.map((initials) => { + const person = peopleByInitials[initials]; + return ( + + ); + })} +
+
+ ))} +
+ ); +} + +type SparklineProps = { + values: number[]; + color: string; + title?: string; +}; + +function Sparkline({ values, color, title }: SparklineProps) { + const width = 80; + const height = 20; + const padding = 2; + + if (values.length === 0) return null; + + const min = Math.min(...values); + const max = Math.max(...values); + const range = Math.max(max - min, 1); + const stepX = (width - padding * 2) / Math.max(values.length - 1, 1); + + const points = values.map((v, i) => { + const x = padding + i * stepX; + const y = padding + (height - padding * 2) * (1 - (v - min) / range); + return `${x.toFixed(1)},${y.toFixed(1)}`; + }); + + const areaPath = + `M ${padding},${height - padding} ` + + points.map((p) => `L ${p}`).join(" ") + + ` L ${width - padding},${height - padding} Z`; + + const linePath = `M ${points.join(" L ")}`; + + const last = points[points.length - 1].split(","); + + return ( + + {title ? {title} : null} + + + + + ); +} + +function ToolGlyph({ tool, small = false }: { tool: string; small?: boolean }) { + const sizeClass = small + ? "h-5 w-5 rounded-[6px]" + : "h-6 w-6 rounded-[7px] md:h-7 md:w-7 md:rounded-[8px]"; + + if (tool === "OpenWork") { + return ( +
+ +
+ ); + } + + const textSizeClass = small + ? "text-[10px] font-semibold" + : "text-[11px] font-semibold md:text-[12px]"; + + const iconMap: Record = { + Cursor: C, + "Figma AI": F, + "Notion AI": N, + "Zendesk AI": Z, + Zed: Z, + Omarchy: O, + "Hugging Face": 🤗, + "Claude Code": CC + }; + + return ( +
+ {iconMap[tool] ?? ( + + )} +
+ ); +} + +function InitialPill({ + initials, + department, + name +}: { + initials: string; + department: string; + name?: string; +}) { + const tooltip = name + ? `${name} · ${department}` + : `${initials} · ${department}`; + + return ( +
+ {initials} +
+ ); +} + +function departmentColor(department: string) { + switch (department) { + case "Engineering": + return "bg-[#F9DADB] text-[#B43035]"; + case "Product": + return "bg-[#DFEAFE] text-[#1D63FF]"; + case "Customer Support": + return "bg-[#DFF5F6] text-[#127B85]"; + case "Marketing": + return "bg-[#FBE6D7] text-[#E56A17]"; + case "Sales": + return "bg-[#E3F4DF] text-[#2C8B39]"; + case "Legal": + return "bg-[#E8EBEF] text-[#5A6886]"; + default: + return "bg-[#EEF2F7] text-[#30405F]"; + } +} + +function sparklineColor(department: string) { + switch (department) { + case "Engineering": + return "#B43035"; + case "Product": + return "#1D63FF"; + case "Customer Support": + return "#127B85"; + case "Marketing": + return "#E56A17"; + case "Sales": + return "#2C8B39"; + case "Legal": + return "#5A6886"; + default: + return "#30405F"; + } +} + +/** + * Color the adoption trend line by direction so users can scan up/down/flat at a glance. + * Uses 3-point rolling averages at each end to avoid false signals on a single spiky day. + */ +function trendDirectionColor(trend: number[]): string { + if (trend.length < 3) return "#637291"; + const startAvg = (trend[0] + trend[1] + trend[2]) / 3; + const endAvg = trend.slice(-3).reduce((a, b) => a + b, 0) / 3; + const delta = endAvg - startAvg; + if (delta > 0.5) return "#18A34A"; // green + if (delta < -0.5) return "#B43035"; // red + return "#637291"; // gray +} + +function toneBg(tone: "violet" | "green" | "blue") { + switch (tone) { + case "violet": + return "bg-[#EDE4FF]"; + case "green": + return "bg-[#E3F3E3]"; + case "blue": + return "bg-[#E4ECFB]"; + } +} + +export default LandingEnterpriseHero; diff --git a/ee/apps/landing/components/landing-enterprise.tsx b/ee/apps/landing/components/landing-enterprise.tsx index 5993de55..070b7ca6 100644 --- a/ee/apps/landing/components/landing-enterprise.tsx +++ b/ee/apps/landing/components/landing-enterprise.tsx @@ -11,6 +11,7 @@ import { useState } from "react"; import { BookCallForm } from "./book-call-form"; import { LandingAppDemoPanel } from "./landing-app-demo-panel"; import { LandingBackground } from "./landing-background"; +import { LandingEnterpriseHero } from "./landing-enterprise-hero"; import { defaultLandingDemoFlowId, landingDemoFlows, @@ -118,15 +119,12 @@ export function LandingEnterprise(props: Props) {
-
- OpenWork enterprise dashboard showing AI adoption, spend, and tool penetration by department -
+
+ +
diff --git a/ee/apps/landing/screenshots/tab-1-departments.png b/ee/apps/landing/screenshots/tab-1-departments.png new file mode 100644 index 00000000..15667901 Binary files /dev/null and b/ee/apps/landing/screenshots/tab-1-departments.png differ diff --git a/ee/apps/landing/screenshots/tab-2-power-users.png b/ee/apps/landing/screenshots/tab-2-power-users.png new file mode 100644 index 00000000..88cd80b3 Binary files /dev/null and b/ee/apps/landing/screenshots/tab-2-power-users.png differ diff --git a/ee/apps/landing/screenshots/tab-3-ai-tools.png b/ee/apps/landing/screenshots/tab-3-ai-tools.png new file mode 100644 index 00000000..60a049e1 Binary files /dev/null and b/ee/apps/landing/screenshots/tab-3-ai-tools.png differ