Sivi UI SDK Sample Implementation
This guide demonstrates a complete implementation of the Sivi UI SDK in a React application. The sample shows how to integrate the Sivi design generation capabilities into a content editor application like Website builders, CMS, Email editors, Banner editors and so on, allowing users to generate and place designs directly within content templates.
Overview
This sample implements a simplified content editor with the following features:
- A template with placeholders for design elements
- Integration with the Sivi UI SDK for AI-powered design generation
- Ability to select generated designs and place them in the template
- Celebration animation when designs are selected. 🎊
Implementation Breakdown
1. Setup and Constants
import './App.css'
import React from 'react'
import ConfettiExplosion from 'react-confetti-explosion';
const IFRAME_CONTAINER_ID = 'sivi-container'
This section imports the required dependencies and defines the container ID where the Sivi widget will be embedded.
2. Template Logic Hook
const useTemplateLogic = ({ imageUrl, handleVisualClick, shapes }) => {
const selectedVisual = React.useRef(null)
const [visualShapes, setVisualShapes] = React.useState(shapes)
const handleShapeClick = (event, id) => {
const width = event.target.offsetWidth
const height = event.target.offsetHeight
selectedVisual.current = id
handleVisualClick && handleVisualClick({
width,
height
})
}
React.useEffect(() => {
if (imageUrl && selectedVisual.current) {
setVisualShapes(prev => {
return {
...prev,
[selectedVisual.current]: {
imageUrl: imageUrl
}
}
})
}
}, [imageUrl])
return {
visualShapes,
handleShapeClick
}
}
What This Does:
- Creates a custom hook to manage the template's design placement logic
- Tracks which placeholder is currently selected using a React ref
- Updates the appropriate placeholder when a new design is selected
- Provides dimensions of the selected area to the Sivi widget for appropriate sizing
3. Template Component
const WebTemplate = ({ handleVisualClick, imageUrl }) => {
const { visualShapes, handleShapeClick } = useTemplateLogic({
imageUrl,
handleVisualClick,
shapes: {
shape1: {
url: null
},
shape2: {
url: null
}
}
})
return (
<div className='w-[600px] h-[700px] bg-gray-100 flex flex-col items-center p-4 gap-4'>
<span className='text-8xl font-bold text-indigo-500'>
Momentum Athletics
</span>
<div className='w-full h-full flex gap-4 flex-row items-center'>
<div onClick={(e) => handleShapeClick(e, 'shape1')} className='cursor-pointer w-1/2 h-full bg-green-200 flex flex-col justify-center items-center'>
{visualShapes.shape1.imageUrl ?
<img src={visualShapes.shape1.imageUrl} alt="Extracted Image" className='w-full h-full object-contain' /> : (
<div className='w-full h-full flex justify-center items-center cursor-pointer'>
<p className='text-gray-500 text-center'>Click to add visuals</p>
</div>
)}
</div>
<div className='w-1/2 h-full flex flex-col items-center'>
<div id="shape2" onClick={(e) => handleShapeClick(e, 'shape2')} className='cursor-pointer w-full h-1/2 bg-blue-200 flex flex-col justify-center items-center'>
{visualShapes.shape2.imageUrl ?
<img src={visualShapes.shape2.imageUrl} alt="Extracted Image" className='w-full h-full object-contain' /> : (
<div className='w-full h-full flex justify-center items-center cursor-pointer'>
<p className='text-gray-500 text-center'>Click to add visuals</p>
</div>
)}
</div>
<div className='w-full h-1/2 flex flex-col justify-center items-center'>
<span className='text-4xl font-bold text-indigo-500 text-center'>
Transform your fitness journey with expert tips and guided training.
</span>
<span className='text-2xl font-bold text-indigo-500'>
Ignite your motivation and get stronger every day.
</span>
</div>
</div>
</div>
</div>
)
}
What This Does:
- Renders a marketing template with placeholders for designs
- Uses the template logic hook to manage state and handle interactions
- Displays placeholders with "Click to add visuals" text when empty
- Shows the selected designs when available
4. Main Application Component
function App() {
let paramsRef = React.useRef(null)
const [isExploding, setIsExploding] = React.useState(false);
const [isVisualOpen, setIsVisualOpen] = React.useState(false)
const [imageUrl, setImageUrl] = React.useState(null)
const [currentTemplate, setCurrentTemplate] = React.useState(1)
const handleVisualClick = ({ width, height }) => {
if (!isVisualOpen) {
setIsVisualOpen(true)
paramsRef.current = {
width,
height
}
} else {
const params = {
type: "custom",
subtype: "custom",
dimension: {
width: paramsRef.current.width,
height: paramsRef.current.height
},
}
window.SIVI.show(params, IFRAME_CONTAINER_ID)
}
}
What This Does:
- Sets up state management for the application
- Handles clicks on template placeholders
- Stores dimensions of clicked areas for the Sivi widget configuration
5. Sivi Widget Initialization
React.useEffect(() => {
if (isVisualOpen) {
if (paramsRef.current) {
const params = {
type: "custom",
subtype: "custom",
dimension: {
width: paramsRef.current.width,
height: paramsRef.current.height
},
prompt: "Create a modern social media post about sustainable fashion",
language: "english",
colors: ["#5662EC", "#EF9AB2"],
numOfVariants: 2,
outputFormat: "png",
config: {
enableDesignEditor: true,
}
}
window.SIVI.show(params, IFRAME_CONTAINER_ID)
paramsRef.current = null
} else {
window.SIVI.show(false, IFRAME_CONTAINER_ID)
}
}
}, [isVisualOpen])
const handleRemoveVisual = () => {
window.SIVI.hide()
setIsVisualOpen(false)
}
What This Does:
- Initializes the Sivi widget when the visual editor should be opened
- Configures the widget with appropriate dimensions and parameters
- Sets up a default prompt and styling options
- Provides a method to close the widget and return to the main interface
6. Event Handling
React.useEffect(() => {
window.SIVI.events(async (event, responseCallback) => {
switch (event.type) {
case 'DESIGN_VARIATION_SELECTED': {
const URL = event.data.variantImageUrl + '?timestamp=' + Date.now()
setIsExploding(true)
setTimeout(() => {
setIsExploding(false)
}, 2000)
setImageUrl(URL)
responseCallback("done")
break
}
}
})
return () => {
window.SIVI.removeEventsCallback()
}
}, [])
What This Does:
- Sets up event listeners for the Sivi widget
- Handles the 'DESIGN_VARIATION_SELECTED' event when a user selects a design
- Updates the application state with the selected design URL
- Triggers a confetti animation to celebrate design selection
- Properly cleans up event listeners when the component unmounts
7. Application UI Rendering
const TemplateCmp = ({ 1: WebTemplate })[currentTemplate]
return (
<div className='h-full w-full'>
<div className='w-full h-16 border-b-2 border-indigo-500 flex flex-row justify-between items-center px-4'>
<span className='text-2xl font-bold text-indigo-500'>
Mail Editor
</span>
<div></div>
</div>
<div className='flex flex-row h-[calc(100%-4rem)] w-full'>
<div className='w-1/4 h-full border-r-2 border-indigo-500 p-4'>
{isVisualOpen ? (
<>
<div id={IFRAME_CONTAINER_ID} className='w-full h-5/6 bg-violet-500 rounded-md border-2 border-indigo-200 overflow-hidden'>
{/* Iframe placeholder */}
</div>
<button className='mt-4 w-full h-12 bg-white-500 text-black p-2 rounded-md transition-all duration-300' onClick={handleRemoveVisual}>
Back to Home
</button>
</>
) : <div className='flex h-full w-full justify-center items-center'>
<button onClick={() => setIsVisualOpen(true)} className='h-12 w-1/2 bg-indigo-500 text-white p-2 rounded-md hover:bg-indigo-600 transition-all duration-300'>
AI Design Studio
</button>
</div>}
</div>
<div className='w-[calc(100%-36rem)] h-full flex justify-center items-center'>
<div className='w-full h-[calc(100%-5rem)] flex justify-center items-center flex-col'>
{isExploding && <ConfettiExplosion />}
<TemplateCmp handleVisualClick={handleVisualClick} imageUrl={imageUrl} />
</div>
</div>
</div>
</div>
)
}
export default App
What This Does:
- Renders the complete application interface with a header and two-panel layout
- Shows either the launch button or the Sivi widget in the left panel
- Displays the content template in the main panel
- Includes the confetti animation when designs are selected
Enterprise Implementation
For enterprise-specific implementation examples, including authentication and user management, see the Enterprise Features Sample Usage.