Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions examples/openui-artifact-demo/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Node
node_modules
.pnpm-store
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Next.js
.next
out

# Git
.git
.gitignore

# Logs
logs
*.log

# Env files
.env
.env.*
!.env.example

# OS files
.DS_Store
Thumbs.db

# Build / cache
dist
build
.turbo
.cache
coverage

# Editor
.vscode
.idea
41 changes: 41 additions & 0 deletions examples/openui-artifact-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
73 changes: 73 additions & 0 deletions examples/openui-artifact-demo/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# syntax=docker/dockerfile:1.7
# --------------------------------------------------
# Build stage
# --------------------------------------------------
FROM node:20-alpine AS builder

WORKDIR /app

RUN apk add --no-cache libc6-compat
ARG PNPM_VERSION=9.12.0
RUN corepack enable && corepack prepare pnpm@${PNPM_VERSION} --activate

ENV NEXT_TELEMETRY_DISABLED=1

COPY pnpm-workspace.yaml package.json pnpm-lock.yaml tsconfig.json ./

COPY packages/openui-cli/package.json ./packages/openui-cli/
COPY packages/react-ui/package.json ./packages/react-ui/
COPY packages/react-headless/package.json ./packages/react-headless/
COPY packages/react-lang/package.json ./packages/react-lang/
COPY examples/openui-chat/package.json ./examples/openui-chat/

RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile --ignore-scripts

COPY packages/openui-cli ./packages/openui-cli
COPY packages/react-ui ./packages/react-ui
COPY packages/react-headless ./packages/react-headless
COPY packages/react-lang ./packages/react-lang
COPY examples/openui-chat ./examples/openui-chat

RUN pnpm --filter @openuidev/cli build
RUN pnpm --filter @openuidev/react-ui build
RUN pnpm --filter @openuidev/react-headless build
RUN pnpm --filter @openuidev/react-lang build

WORKDIR /app/examples/openui-chat
RUN node /app/packages/openui-cli/dist/index.js generate src/library.ts --out src/generated/system-prompt.txt \
&& pnpm build



# --------------------------------------------------
# Runtime stage
# --------------------------------------------------
FROM node:20-alpine AS runner

WORKDIR /app

RUN apk add --no-cache libc6-compat

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000 HOSTNAME=0.0.0.0

RUN addgroup -S nodejs && adduser -S nextjs -G nodejs
USER nextjs

# Copy full standalone output to avoid brittle partial-copy assumptions
COPY --from=builder --chown=nextjs:nodejs /app/examples/openui-chat/.next/standalone ./

# Static assets expected by Next at runtime
COPY --from=builder --chown=nextjs:nodejs /app/examples/openui-chat/.next/static ./examples/openui-chat/.next/static

# If your app has a public directory, include this line
# COPY --from=builder --chown=nextjs:nodejs /app/examples/openui-chat/public ./examples/openui-chat/public

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:3000').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"

CMD ["node", "examples/openui-chat/server.js"]
46 changes: 46 additions & 0 deletions examples/openui-artifact-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# OpenUI Artifact Demo

A demo application showcasing the OpenUI artifact system for displaying generated code in a resizable side panel.

## Features

- **Artifact Code Blocks**: AI-generated code appears as compact previews in chat
- **Side Panel**: Click "View Code" to open the full code in a resizable artifact panel
- **Syntax Highlighting**: Full Prism-based syntax highlighting in the artifact panel
- **Multiple Artifacts**: Multiple code blocks per conversation, one active at a time
- **Copy to Clipboard**: One-click code copying from the artifact panel

## Getting Started

```bash
# Install dependencies (from repo root)
pnpm install

# Generate the system prompt
pnpm --filter openui-artifact-demo generate:prompt

# Start the development server
pnpm --filter openui-artifact-demo dev
```

Set your OpenAI API key:
```bash
export OPENAI_API_KEY=your-key-here
```

## How It Works

This example extends the standard OpenUI chat library with a custom `ArtifactCodeBlock` component that integrates with the OpenUI artifact system:

1. User asks for code (e.g., "Build me a React login form")
2. AI generates a response using `ArtifactCodeBlock` components
3. Each code block shows an inline preview in the chat
4. Clicking "View Code" opens the full code in the artifact side panel
5. The panel is resizable and supports syntax highlighting + copy

## Architecture

- `src/components/ArtifactCodeBlock/` — Custom genui component with inline preview and artifact panel view
- `src/library.ts` — Extended component library with ArtifactCodeBlock
- `src/app/page.tsx` — Main page using FullScreen layout
- `src/app/api/chat/route.ts` — API route for OpenAI streaming
18 changes: 18 additions & 0 deletions examples/openui-artifact-demo/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";

const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
]),
]);

export default eslintConfig;
9 changes: 9 additions & 0 deletions examples/openui-artifact-demo/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
output: "standalone",
turbopack: {},
transpilePackages: ["@openuidev/react-ui", "@openuidev/react-headless", "@openuidev/react-lang"],
};

export default nextConfig;
36 changes: 36 additions & 0 deletions examples/openui-artifact-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "openui-artifact-demo",
"version": "0.1.0",
"private": true,
"scripts": {
"generate:prompt": "pnpm --filter @openuidev/cli build && pnpm exec openui generate src/library.ts --out src/generated/system-prompt.txt",
"dev": "pnpm generate:prompt && next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
},
"dependencies": {
"@openuidev/react-headless": "workspace:*",
"@openuidev/react-lang": "workspace:*",
"@openuidev/react-ui": "workspace:*",
"lucide-react": "^0.575.0",
"react-syntax-highlighter": "^15.6.1",
"zod": "^4.0.0",
"next": "16.1.6",
"openai": "^6.22.0",
"react": "19.2.3",
"react-dom": "19.2.3"
},
"devDependencies": {
"@openuidev/cli": "workspace:*",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/react-syntax-highlighter": "^15.5.13",
"eslint": "^9",
"eslint-config-next": "16.1.6",
"tailwindcss": "^4",
"typescript": "^5"
}
}
7 changes: 7 additions & 0 deletions examples/openui-artifact-demo/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};

export default config;
Loading
Loading