From 3fe41d2fb7f643c5846682c832308322f5feaa58 Mon Sep 17 00:00:00 2001 From: pitoi Date: Tue, 30 Dec 2025 15:39:15 +0000 Subject: [PATCH] implement demo mode with in-memory mock data --- .../agent-playground/app/mock-scenarios.ts | 238 ++++++++++++++++++ .../e2e/fixtures/session-fixtures.ts | 168 +++++++++++++ .../react-grab/e2e/fixtures/theme-fixtures.ts | 102 ++++++++ packages/website/lib/mock-data.ts | 218 ++++++++++++++++ 4 files changed, 726 insertions(+) create mode 100644 packages/agent-playground/app/mock-scenarios.ts create mode 100644 packages/react-grab/e2e/fixtures/session-fixtures.ts create mode 100644 packages/react-grab/e2e/fixtures/theme-fixtures.ts create mode 100644 packages/website/lib/mock-data.ts diff --git a/packages/agent-playground/app/mock-scenarios.ts b/packages/agent-playground/app/mock-scenarios.ts new file mode 100644 index 000000000..c873d6266 --- /dev/null +++ b/packages/agent-playground/app/mock-scenarios.ts @@ -0,0 +1,238 @@ +import type { AgentSession, Theme } from "../../react-grab/src/types"; + +interface MockScenario { + id: string; + name: string; + description: string; + session: AgentSession; + theme: Theme; +} + +export const MOCK_SCENARIOS: MockScenario[] = [ + { + id: "scenario-button-styling", + name: "Button Styling", + description: "Style a button with colors and effects", + session: { + id: "playground-session-1", + context: { + content: [''], + prompt: + "Make this button stand out with a gradient background and shadow", + options: {}, + }, + lastStatus: "Ready to apply changes", + isStreaming: false, + createdAt: Date.now(), + lastUpdatedAt: Date.now(), + position: { x: 100, y: 100 }, + selectionBounds: [ + { + x: 50, + y: 50, + width: 140, + height: 45, + borderRadius: "8px", + transform: "translate(0, 0)", + }, + ], + tagName: "button", + componentName: "CTAButton", + }, + theme: { + enabled: true, + hue: 280, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + }, + }, + { + id: "scenario-card-layout", + name: "Card Layout", + description: "Adjust card spacing and shadows", + session: { + id: "playground-session-2", + context: { + content: [ + '
Feature

Feature Title

Feature description text

', + ], + prompt: + "Improve the card layout with better spacing and a subtle shadow", + options: {}, + }, + lastStatus: "Changes applied", + isStreaming: false, + createdAt: Date.now() - 60000, + lastUpdatedAt: Date.now() - 55000, + position: { x: 200, y: 150 }, + selectionBounds: [ + { + x: 150, + y: 120, + width: 300, + height: 200, + borderRadius: "12px", + transform: "translate(0, 0)", + }, + ], + tagName: "div", + componentName: "FeatureCard", + }, + theme: { + enabled: true, + hue: 200, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + }, + }, + { + id: "scenario-form-input", + name: "Form Input", + description: "Style form input with focus states", + session: { + id: "playground-session-3", + context: { + content: [ + '', + ], + prompt: "Add focus states and improve the input styling", + options: {}, + }, + lastStatus: "Streaming updates…", + isStreaming: true, + createdAt: Date.now() - 10000, + lastUpdatedAt: Date.now() - 1000, + position: { x: 150, y: 250 }, + selectionBounds: [ + { + x: 100, + y: 220, + width: 320, + height: 48, + borderRadius: "6px", + transform: "translate(0, 0)", + }, + ], + tagName: "input", + }, + theme: { + enabled: true, + hue: 140, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + }, + }, + { + id: "scenario-navigation", + name: "Navigation Bar", + description: "Responsive navigation with hover effects", + session: { + id: "playground-session-4", + context: { + content: [ + '', + ], + prompt: + "Make this navigation responsive and add smooth hover transitions", + options: {}, + }, + lastStatus: "Ready to apply", + isStreaming: false, + createdAt: Date.now() - 120000, + lastUpdatedAt: Date.now() - 115000, + position: { x: 50, y: 50 }, + selectionBounds: [ + { + x: 20, + y: 20, + width: 600, + height: 60, + borderRadius: "0", + transform: "translate(0, 0)", + }, + ], + tagName: "nav", + componentName: "MainNavigation", + }, + theme: { + enabled: true, + hue: 0, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + }, + }, + { + id: "scenario-minimal-theme", + name: "Minimal Theme", + description: "Test with minimal UI overlays", + session: { + id: "playground-session-5", + context: { + content: ['

Minimal Example

'], + prompt: "Apply minimal styling with reduced visual noise", + options: {}, + }, + lastStatus: "Changes applied successfully", + isStreaming: false, + createdAt: Date.now() - 240000, + lastUpdatedAt: Date.now() - 235000, + position: { x: 180, y: 120 }, + selectionBounds: [ + { + x: 120, + y: 80, + width: 400, + height: 100, + borderRadius: "4px", + transform: "translate(0, 0)", + }, + ], + tagName: "div", + componentName: "Container", + }, + theme: { + enabled: true, + hue: 0, + selectionBox: { enabled: true }, + dragBox: { enabled: false }, + grabbedBoxes: { enabled: false }, + elementLabel: { enabled: true }, + crosshair: { enabled: false }, + toolbar: { enabled: true }, + }, + }, +]; + +export const getScenarioById = ( + scenarioId: string, +): MockScenario | undefined => { + return MOCK_SCENARIOS.find((scenario) => scenario.id === scenarioId); +}; + +export const getScenarioNames = (): Array<{ + id: string; + name: string; + description: string; +}> => { + return MOCK_SCENARIOS.map((scenario) => ({ + id: scenario.id, + name: scenario.name, + description: scenario.description, + })); +}; diff --git a/packages/react-grab/e2e/fixtures/session-fixtures.ts b/packages/react-grab/e2e/fixtures/session-fixtures.ts new file mode 100644 index 000000000..8b58c302c --- /dev/null +++ b/packages/react-grab/e2e/fixtures/session-fixtures.ts @@ -0,0 +1,168 @@ +import type { AgentSession } from "../../src/types"; + +export const TEST_SESSION_BASIC: AgentSession = { + id: "test-session-basic", + context: { + content: [""], + prompt: "Style this button", + options: {}, + }, + lastStatus: "Completed", + isStreaming: false, + createdAt: Date.now() - 10000, + lastUpdatedAt: Date.now() - 9000, + position: { x: 100, y: 100 }, + selectionBounds: [ + { + x: 50, + y: 50, + width: 100, + height: 40, + borderRadius: "4px", + transform: "translate(0, 0)", + }, + ], + tagName: "button", +}; + +export const TEST_SESSION_STREAMING: AgentSession = { + id: "test-session-streaming", + context: { + content: ['
Card Content
'], + prompt: "Update card styling", + options: {}, + }, + lastStatus: "Processing…", + isStreaming: true, + createdAt: Date.now() - 5000, + lastUpdatedAt: Date.now() - 1000, + position: { x: 200, y: 150 }, + selectionBounds: [ + { + x: 150, + y: 100, + width: 250, + height: 150, + borderRadius: "8px", + transform: "translate(0, 0)", + }, + ], + tagName: "div", + componentName: "Card", +}; + +export const TEST_SESSION_WITH_ERROR: AgentSession = { + id: "test-session-error", + context: { + content: [''], + prompt: "Apply invalid CSS", + options: {}, + }, + lastStatus: "Failed", + isStreaming: false, + createdAt: Date.now() - 15000, + lastUpdatedAt: Date.now() - 14000, + position: { x: 150, y: 250 }, + selectionBounds: [ + { + x: 100, + y: 220, + width: 300, + height: 45, + borderRadius: "4px", + transform: "translate(0, 0)", + }, + ], + tagName: "input", + error: "Invalid CSS syntax", +}; + +export const TEST_SESSION_WITH_COMPONENT: AgentSession = { + id: "test-session-component", + context: { + content: [''], + prompt: "Style navigation", + options: {}, + }, + lastStatus: "Completed successfully", + isStreaming: false, + createdAt: Date.now() - 30000, + lastUpdatedAt: Date.now() - 28000, + position: { x: 50, y: 50 }, + selectionBounds: [ + { + x: 20, + y: 20, + width: 400, + height: 50, + borderRadius: "0", + transform: "translate(0, 0)", + }, + ], + tagName: "nav", + componentName: "Navigation", +}; + +export const TEST_SESSION_NESTED: AgentSession = { + id: "test-session-nested", + context: { + content: ["
Nested Text
"], + prompt: "Update nested element", + options: {}, + sessionId: "test-session-basic", + }, + lastStatus: "In progress", + isStreaming: true, + createdAt: Date.now() - 3000, + lastUpdatedAt: Date.now() - 500, + position: { x: 180, y: 120 }, + selectionBounds: [ + { + x: 140, + y: 90, + width: 180, + height: 80, + borderRadius: "4px", + transform: "translate(0, 0)", + }, + ], + tagName: "strong", +}; + +export const ALL_TEST_SESSIONS: AgentSession[] = [ + TEST_SESSION_BASIC, + TEST_SESSION_STREAMING, + TEST_SESSION_WITH_ERROR, + TEST_SESSION_WITH_COMPONENT, + TEST_SESSION_NESTED, +]; + +export const createTestSession = ( + overrides: Partial = {}, +): AgentSession => { + return { + id: `test-session-${Date.now()}`, + context: { + content: ["
Test Element
"], + prompt: "Test prompt", + options: {}, + }, + lastStatus: "Ready", + isStreaming: false, + createdAt: Date.now(), + lastUpdatedAt: Date.now(), + position: { x: 100, y: 100 }, + selectionBounds: [ + { + x: 50, + y: 50, + width: 200, + height: 100, + borderRadius: "4px", + transform: "translate(0, 0)", + }, + ], + tagName: "div", + ...overrides, + }; +}; diff --git a/packages/react-grab/e2e/fixtures/theme-fixtures.ts b/packages/react-grab/e2e/fixtures/theme-fixtures.ts new file mode 100644 index 000000000..1ec10b45e --- /dev/null +++ b/packages/react-grab/e2e/fixtures/theme-fixtures.ts @@ -0,0 +1,102 @@ +import type { Theme } from "../../src/types"; + +export const TEST_THEME_DEFAULT: Theme = { + enabled: true, + hue: 0, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, +}; + +export const TEST_THEME_BLUE: Theme = { + enabled: true, + hue: 200, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, +}; + +export const TEST_THEME_PURPLE: Theme = { + enabled: true, + hue: 280, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, +}; + +export const TEST_THEME_GREEN: Theme = { + enabled: true, + hue: 140, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, +}; + +export const TEST_THEME_MINIMAL: Theme = { + enabled: true, + hue: 0, + selectionBox: { enabled: true }, + dragBox: { enabled: false }, + grabbedBoxes: { enabled: false }, + elementLabel: { enabled: true }, + crosshair: { enabled: false }, + toolbar: { enabled: true }, +}; + +export const TEST_THEME_DISABLED: Theme = { + enabled: false, + hue: 0, + selectionBox: { enabled: false }, + dragBox: { enabled: false }, + grabbedBoxes: { enabled: false }, + elementLabel: { enabled: false }, + crosshair: { enabled: false }, + toolbar: { enabled: false }, +}; + +export const TEST_THEME_SELECTION_ONLY: Theme = { + enabled: true, + hue: 180, + selectionBox: { enabled: true }, + dragBox: { enabled: false }, + grabbedBoxes: { enabled: false }, + elementLabel: { enabled: false }, + crosshair: { enabled: false }, + toolbar: { enabled: false }, +}; + +export const ALL_TEST_THEMES: Record = { + default: TEST_THEME_DEFAULT, + blue: TEST_THEME_BLUE, + purple: TEST_THEME_PURPLE, + green: TEST_THEME_GREEN, + minimal: TEST_THEME_MINIMAL, + disabled: TEST_THEME_DISABLED, + selectionOnly: TEST_THEME_SELECTION_ONLY, +}; + +export const createTestTheme = (overrides: Partial = {}): Theme => { + return { + enabled: true, + hue: 0, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + ...overrides, + }; +}; diff --git a/packages/website/lib/mock-data.ts b/packages/website/lib/mock-data.ts new file mode 100644 index 000000000..6dcf4e9b8 --- /dev/null +++ b/packages/website/lib/mock-data.ts @@ -0,0 +1,218 @@ +import type { AgentSession, Theme } from "../../react-grab/src/types"; +import type { ToolbarState } from "../../react-grab/src/components/toolbar/state"; + +export const isDemoMode = (): boolean => { + if (typeof window === "undefined") return false; + return window.location.search.includes("demo=true"); +}; + +export const MOCK_SESSIONS: AgentSession[] = [ + { + id: "session-demo-1", + context: { + content: [''], + prompt: "Make this button blue with rounded corners", + options: {}, + }, + lastStatus: "Successfully applied style changes", + isStreaming: false, + createdAt: Date.now() - 300000, + lastUpdatedAt: Date.now() - 295000, + position: { x: 120, y: 100 }, + selectionBounds: [ + { + x: 50, + y: 50, + width: 120, + height: 40, + borderRadius: "4px", + transform: "translate(0, 0)", + }, + ], + tagName: "button", + componentName: "SubmitButton", + }, + { + id: "session-demo-2", + context: { + content: [ + '

Product Title

Product description goes here

', + ], + prompt: "Add a subtle shadow and increase spacing", + options: {}, + }, + lastStatus: "Changes applied successfully", + isStreaming: false, + createdAt: Date.now() - 180000, + lastUpdatedAt: Date.now() - 175000, + position: { x: 300, y: 200 }, + selectionBounds: [ + { + x: 200, + y: 150, + width: 280, + height: 160, + borderRadius: "8px", + transform: "translate(0, 0)", + }, + ], + tagName: "div", + componentName: "ProductCard", + }, + { + id: "session-demo-3", + context: { + content: [''], + prompt: "Make navigation responsive and add hover effects", + options: {}, + sessionId: "session-demo-2", + }, + lastStatus: "Streaming updates…", + isStreaming: true, + createdAt: Date.now() - 30000, + lastUpdatedAt: Date.now() - 1000, + position: { x: 150, y: 50 }, + selectionBounds: [ + { + x: 20, + y: 20, + width: 400, + height: 50, + borderRadius: "0", + transform: "translate(0, 0)", + }, + ], + tagName: "nav", + }, + { + id: "session-demo-4", + context: { + content: [''], + prompt: "Style this input with focus states", + options: {}, + }, + lastStatus: "Failed to apply changes", + isStreaming: false, + createdAt: Date.now() - 90000, + lastUpdatedAt: Date.now() - 85000, + position: { x: 250, y: 300 }, + selectionBounds: [ + { + x: 100, + y: 250, + width: 300, + height: 45, + borderRadius: "4px", + transform: "translate(0, 0)", + }, + ], + tagName: "input", + error: "Unable to parse CSS syntax", + }, +]; + +export const MOCK_TOOLBAR_STATES: Record = { + bottom: { + edge: "bottom", + ratio: 0.5, + collapsed: false, + }, + top: { + edge: "top", + ratio: 0.3, + collapsed: false, + }, + left: { + edge: "left", + ratio: 0.4, + collapsed: true, + }, + right: { + edge: "right", + ratio: 0.6, + collapsed: false, + }, +}; + +export const MOCK_THEMES: Record = { + default: { + enabled: true, + hue: 0, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + }, + blue: { + enabled: true, + hue: 200, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + }, + purple: { + enabled: true, + hue: 280, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + }, + green: { + enabled: true, + hue: 140, + selectionBox: { enabled: true }, + dragBox: { enabled: true }, + grabbedBoxes: { enabled: true }, + elementLabel: { enabled: true }, + crosshair: { enabled: true }, + toolbar: { enabled: true }, + }, + minimal: { + enabled: true, + hue: 0, + selectionBox: { enabled: true }, + dragBox: { enabled: false }, + grabbedBoxes: { enabled: false }, + elementLabel: { enabled: true }, + crosshair: { enabled: false }, + toolbar: { enabled: true }, + }, +}; + +export const getMockSessions = (): AgentSession[] => { + return isDemoMode() ? MOCK_SESSIONS : []; +}; + +export const getMockToolbarState = ( + key: string = "bottom", +): ToolbarState | null => { + if (!isDemoMode()) return null; + return MOCK_TOOLBAR_STATES[key] || MOCK_TOOLBAR_STATES.bottom; +}; + +export const getMockTheme = (key: string = "default"): Theme | null => { + if (!isDemoMode()) return null; + return MOCK_THEMES[key] || MOCK_THEMES.default; +}; + +export const initializeDemoMode = (): { + sessions: AgentSession[]; + toolbarState: ToolbarState; + theme: Theme; +} | null => { + if (!isDemoMode()) return null; + + return { + sessions: MOCK_SESSIONS, + toolbarState: MOCK_TOOLBAR_STATES.bottom, + theme: MOCK_THEMES.default, + }; +};