Skip to content

feat: wrap up and enhanced canvas page - #2302

Merged
smakosh merged 5 commits into
theopenco:mainfrom
amelitoalcuitas:feat/playground-canvas-mode
May 16, 2026
Merged

smakosh merged 5 commits into
theopenco:mainfrom
amelitoalcuitas:feat/playground-canvas-mode

Conversation

@amelitoalcuitas

@amelitoalcuitas amelitoalcuitas commented May 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Canvas playground with JSON editor, live preview, and templates
    • AI-powered spec generation (streaming)
    • Six chart types (bar, line, area, pie, radar, radial bar) with interactive legends/tooltips
    • Export canvas to PNG and PDF
    • New reusable Card and Chart UI components
  • UX

    • Improved theme switching and added Canvas navigation entries across sidebars and headers

Review Change Stack

smakosh and others added 2 commits May 16, 2026 09:05
@coderabbitai

coderabbitai Bot commented May 16, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: eeed6fef-0dd7-4868-bc3a-5a58b27dd316

📥 Commits

Reviewing files that changed from the base of the PR and between c008b7f and 02765c6.

📒 Files selected for processing (3)
  • apps/playground/src/app/api/canvas/generate/route.ts
  • apps/playground/src/app/canvas/page.tsx
  • apps/playground/src/components/ui/chart.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/playground/src/app/api/canvas/generate/route.ts
  • apps/playground/src/app/canvas/page.tsx

Walkthrough

Adds a Canvas playground: JSON-spec editor + live preview, streaming LLM spec generation API, chart primitives and chart components, templates and exports (PNG/PDF), Canvas UI/sidebar, and theme/navigation updates across the playground.

Changes

Canvas Editor Implementation

Layer / File(s) Summary
Dependencies and Next.js configuration
apps/playground/next.config.ts, apps/playground/package.json
Adds @json-render packages, recharts, html-to-image, jspdf, updates zod to 4.3.6, and configures serverExternalPackages in Next.js config.
Chart UI primitives
apps/playground/src/components/ui/card.tsx, apps/playground/src/components/ui/chart.tsx
Adds Card UI primitives and ChartContainer/ChartStyle with tooltip/legend content, payload-config helper, and chart context/provider exports.
Chart component implementations
apps/playground/src/lib/canvas/chart-components.tsx
Implements Recharts-based Bar/Line/Area/Pie/Radar/RadialBar components with shared color handling, config builders, and empty-data fallbacks.
Canvas infrastructure
apps/playground/src/lib/canvas/chart-definitions.ts, apps/playground/src/lib/canvas/catalog.ts, apps/playground/src/lib/canvas/registry.tsx, apps/playground/src/lib/canvas/templates.ts
Defines Zod schemas for chart props, builds shadcn + chart catalogs, creates component registry (including wrapped charts), and provides templates plus an empty spec.
Canvas spec generation API
apps/playground/src/app/api/canvas/generate/route.ts
New POST route that authenticates via getUser(), validates prompt, reads API key from playground cookies, resolves gateway baseURL, calls streamText with catalog prompt, and returns a streaming text response (exports maxDuration = 300).
Canvas page server component
apps/playground/src/app/canvas/page.tsx
Server page that fetches models/providers and org/project data, derives selectedOrganization/selectedProject (with last-used cookie fallback), and renders CanvasPageClient with LastUsedProjectTracker when applicable.
Canvas editor client
apps/playground/src/components/playground/canvas-page-client.tsx
Client component managing JSON spec editor/preview, streaming generation with incremental compilation and abort, template loading, PNG/PDF export via html-to-image/jspdf, reset confirmation, and responsive UI (mobile sheet vs desktop split).
Canvas sidebar navigation
apps/playground/src/components/playground/canvas-sidebar.tsx
Adds CanvasSidebar with unauthenticated/authenticated states, "New Canvas" action, CreditsDisplay, user dropdown with theme toggle and logout that clears cookies, resets PostHog, and redirects via signOut.
Navigation integration and theme consolidation
apps/playground/src/components/playground/chat-sidebar.tsx, apps/playground/src/components/playground/image-sidebar.tsx, apps/playground/src/components/playground/org-sidebar.tsx, apps/playground/src/components/playground/video-sidebar.tsx, apps/playground/src/components/playground/image-header.tsx, apps/playground/src/components/playground/org-header.tsx, apps/playground/src/components/playground/video-header.tsx, apps/playground/src/components/playground/group-chat-client.tsx, apps/playground/src/components/playground/chat-ui.tsx
Adds Canvas route with PenTool icon across sidebars, removes ThemeToggle/Dashboard from headers, and consolidates theme switching into sidebar user dropdowns; minor ChatUI input style tweak.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Canvas as CanvasPageClient
  participant API as POST /api/canvas/generate
  participant Auth as getUser()
  participant Gateway as LLM Gateway
  participant Storage as Preview/Spec State
  User->>Canvas: click generate with prompt
  Canvas->>API: POST {prompt, model}
  API->>Auth: validate user
  Auth-->>API: user data
  API->>Gateway: streamText with catalog system prompt
  Gateway-->>API: stream chunks
  API-->>Canvas: text stream
  Canvas->>Canvas: compileSpecStream incrementally
  Canvas->>Storage: update preview + editor
  Canvas-->>User: render live preview
Loading
sequenceDiagram
  participant User
  participant Canvas as CanvasPageClient
  participant HTMLtoImg as html-to-image
  participant JSPDF as jspdf
  User->>Canvas: click export
  Canvas->>Canvas: detect background color
  User->>Canvas: select PNG or PDF
  Canvas->>HTMLtoImg: convert preview DOM to PNG
  HTMLtoImg-->>Canvas: PNG blob
  Canvas-->>User: download PNG
  Canvas->>JSPDF: create PDF with dimensions
  JSPDF->>HTMLtoImg: convert to image for PDF
  HTMLtoImg-->>JSPDF: image data
  JSPDF-->>Canvas: PDF blob
  Canvas-->>User: download PDF
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • smakosh
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'wrap up and enhanced canvas page' is vague and non-descriptive, using generic terms like 'wrap up' that don't convey meaningful information about the specific changes introduced in this substantial feature addition. Consider a more specific title that highlights the primary feature, such as 'feat: add canvas playground with JSON spec editor and export capabilities' or 'feat: introduce canvas mode with live preview and PDF/PNG export'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/playground/src/app/api/canvas/generate/route.ts`:
- Around line 25-27: Wrap the JSON parsing in route.ts that calls await
req.json() (the code that assigns body as CanvasGenerateBody and extracts
prompt/model and systemPrompt) in a try/catch to handle malformed JSON;
specifically catch SyntaxError from req.json() and return a 400 response with a
clear error message instead of letting it bubble up to a 500, then proceed with
existing validation/processing only when parsing succeeds.
- Around line 16-71: This Next.js route's backend logic (POST, createLLMGateway,
streamText, cookieApiKey, selectedModel, systemPrompt, messages) must be moved
behind the internal API layer: either implement a new backend endpoint in the
API app that encapsulates the current generation logic (create the POST handler
in the API service that performs auth, reads cookie API key, builds
createLLMGateway, calls streamText and returns the stream) or replace this
route's body with a call to the generated typed internal API client from the
playground app (invoke the new API endpoint, forwarding prompt/model and letting
the API handle auth and gateway creation), then return the client response as
the route response; make sure to remove direct LLM gateway usage from the
playground and reference the same symbols (selectedModel, systemPrompt,
messages) when moving logic so behavior remains identical.

In `@apps/playground/src/app/canvas/page.tsx`:
- Around line 59-61: The selection logic for selectedOrganization uses (orgId ?
organizations.find((o) => o.id === orgId) : organizations[0]) ?? null which
makes selectedOrganization null when orgId exists but find returns undefined;
change the logic in the page component so that when orgId is provided but no
matching organization is found you fall back to organizations[0] (or null only
if organizations is empty). Update the expression that computes
selectedOrganization (referencing selectedOrganization, orgId, and
organizations) to prefer the found organization if present, otherwise default to
the first organization in the list.

In `@apps/playground/src/components/playground/canvas-page-client.tsx`:
- Around line 150-158: Replace the raw fetch call that posts to
"/api/canvas/generate" with the typed client from "`@/lib/fetch-client`"
(useFetchClient or useApi); locate the fetch usage inside the function where
prompt, selectedModel and abortRef.current.signal are used and call the
generated client method for the canvas.generate endpoint instead, passing the
same payload ({ prompt, model: selectedModel }) and the abort signal, then
handle the typed response and errors consistently with the rest of the component
(e.g., preserve existing response handling logic and error/cleanup behavior).
- Around line 252-253: The dynamic import of html-to-image (and analogous
dynamic import of jspdf) inside the client component should be replaced with
top-level imports to satisfy the TS/TSX guideline; remove the await
import("html-to-image") and instead add top-level imports for html-to-image
(e.g., import { toPng } from "html-to-image") and jspdf (e.g., import jsPDF from
"jspdf") at the top of
apps/playground/src/components/playground/canvas-page-client.tsx, then update
the code that calls toPng and jsPDF to use the imported symbols directly (ensure
any existing variable names like toPng and jsPDF are referenced consistently).

In `@apps/playground/src/components/ui/chart.tsx`:
- Around line 239-243: The tooltip currently hides numeric zero because it uses
a truthy guard on item.value; update the render condition in the tooltip (the
JSX block that checks item.value and renders the <span> with className
"font-mono font-medium text-foreground tabular-nums") to explicitly allow 0 by
checking for null/undefined instead (e.g., item.value != null or item.value !==
null && item.value !== undefined) so zero values are displayed while still
hiding null/undefined.
- Around line 83-101: The injected stylesheet built in the style tag using
dangerouslySetInnerHTML directly interpolates id, theme keys from THEMES and
color strings from colorConfig; fix by escaping and validating all CSS tokens
before interpolation: use CSS.escape(id) and CSS.escape(theme) for selectors,
map config keys through CSS.escape for variable names, and validate/whitelist
color values (e.g., allow only hex/#rgb(a) or known color names) or otherwise
skip invalid colors before building the string in the style block; update the
code around THEMES, id, and colorConfig usage inside the dangerouslySetInnerHTML
construction to apply these sanitizers and drop/nullify any invalid entries so
no untrusted values are injected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 67a0471d-4f37-465b-bf6b-5dc07d5e8ece

📥 Commits

Reviewing files that changed from the base of the PR and between b159332 and c008b7f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • apps/playground/next.config.ts
  • apps/playground/package.json
  • apps/playground/src/app/api/canvas/generate/route.ts
  • apps/playground/src/app/canvas/page.tsx
  • apps/playground/src/components/playground/canvas-page-client.tsx
  • apps/playground/src/components/playground/canvas-sidebar.tsx
  • apps/playground/src/components/playground/chat-sidebar.tsx
  • apps/playground/src/components/playground/chat-ui.tsx
  • apps/playground/src/components/playground/group-chat-client.tsx
  • apps/playground/src/components/playground/image-header.tsx
  • apps/playground/src/components/playground/image-sidebar.tsx
  • apps/playground/src/components/playground/org-header.tsx
  • apps/playground/src/components/playground/org-sidebar.tsx
  • apps/playground/src/components/playground/video-header.tsx
  • apps/playground/src/components/playground/video-sidebar.tsx
  • apps/playground/src/components/ui/card.tsx
  • apps/playground/src/components/ui/chart.tsx
  • apps/playground/src/lib/canvas/catalog.ts
  • apps/playground/src/lib/canvas/chart-components.tsx
  • apps/playground/src/lib/canvas/chart-definitions.ts
  • apps/playground/src/lib/canvas/registry.tsx
  • apps/playground/src/lib/canvas/templates.ts
💤 Files with no reviewable changes (4)
  • apps/playground/src/components/playground/group-chat-client.tsx
  • apps/playground/src/components/playground/video-header.tsx
  • apps/playground/src/components/playground/image-header.tsx
  • apps/playground/src/components/playground/org-header.tsx

Comment thread apps/playground/src/app/api/canvas/generate/route.ts
Comment thread apps/playground/src/app/api/canvas/generate/route.ts Outdated
Comment thread apps/playground/src/app/canvas/page.tsx Outdated
Comment thread apps/playground/src/components/playground/canvas-page-client.tsx
Comment thread apps/playground/src/components/playground/canvas-page-client.tsx
Comment thread apps/playground/src/components/ui/chart.tsx
Comment thread apps/playground/src/components/ui/chart.tsx Outdated
@smakosh
smakosh enabled auto-merge May 16, 2026 22:38
@smakosh
smakosh added this pull request to the merge queue May 16, 2026
Merged via the queue into theopenco:main with commit 574af63 May 16, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants