# Survey Content Preview
## Why do we need content preview?
- To reduce clinet anxiety.
- To show page style change in time.

## Methods
### 1. Copy page style and implement content preview directly in content editor
```jsx
export default function ContentEditor () {
const [color, setColor] = useState('#FFFFFF')
return (
<div>
<ContentForm color={color} setColor={setColor} />
{/* Clone styles from content page */}
<ContentPreview color={color} />
</div>
)
}
```
- Pros:
- Brute, Easy, and Effective.
- Different frontend frameworks among content page and content editor are acceptable.
- Cons:
- Copy / paste.
- Hard to maintenance in the future.
- Preview and page are not in the same repo.
- Need to handle viewport issue.
- Use Case:
- Pages with simple style and simple bussiness logic.
### 2. Use iframe in content editor to connect with content page and set style of it through message api
```jsx
const contentPreviewUrl = 'https://content/preview'
export default function ContentEditor () {
const ref = useRef(null)
// Use this additional boolean flag to prevent iframe sending message to iframe before it's ready.
const [isIframeLoaded, setIsIframeLoaded] = useState(false)
const [color, setColor] = useState('#FFFFFF')
useEffect(() => {
if (ref.current && isIframeLoaded) {
ref.current?.contentWindow?.postMessage({ key: 'backgroundColor', value: color }, contentPreviewUrl)
}
}, [isIframeLoaded, ref])
return (
<div>
<ContentForm color={color} />
<iframe ref={ref} src={contentPreviewUrl} lazy onLoad={() => setIsIframeLoaded(true)} />
</div>
)
}
```
```vue
<template>
<div>
<button type="button" style={{ backgroundColor }} />
</div>
</template>
<script lang="js" setup>
const backgroundColor = ref('')
const handleMessage = () => {
// Should verify e.origin to trust only OAPlus origin by phase
if (e.origin !== 'http://{safety-parent-origin-here}') {
return
}
switch (e.data.key) {
// You can use cloneDeepRight if event data is nested,
// so you don't need to handle multiple key action here.
case 'backgroundColor':
this.backgroundColor = e.data.value
break
default:
console.log('mismatched key!')
}
}
window.addEventListener('message', handleMessage)
onUnmounted(() => {
window.removeEventListener('message', handleMessage)
})
</script>
```
- Pros:
- Different frontend frameworks among content page and content editor are acceptable.
- Reusable components.
- Preview and page are in the same repo.
- Cons:
- Take time to refactor pure components.
- No need to handle viewport issue.
- Use Case:
- Content page and content editor are based on different frontend framwork.
- Pages with complicated style, special bussiness logic, and lacks of UI freedom.
### 3. Extract component library and apply with both content page and content editor
```jsx
import { Button } from '@xxx/ui-library'
export default function ContentEditable () {
const [color, setColor] = useState('#FFFFFF')
return (
<div>
<ContentForm color={color} setColor={setColor} />
<div>
{/* Compose content preview with ui library */}
<Button type="button" color={color} />
</div>
</div>
)
}
```
```jsx
import { Button } from '@xxx/ui-library'
export default function ContentPage () {
const color = '#FFFFFF'
const handleButtonClick = () => {
console.log('Do some bussiness logic')
}
return (
<div>
<Button type="button" color={color} onClick={handleButtonClick} />
</div>
)
}
```
- Pros:
- Reusable components.
- Cons:
- Same frontend framework among repos are required (or web components).
- Take time to extract components or make repo using the same frontend framework.
- Preview and page are not in the same repo.
- Need to handle viewport issue.
- Case:
- Content page and content editor are based on same frontend framwork.
- Pages with complicated style, special bussiness logic, and lacks of UI freedom.
## Conclusion
My team uses method 2 (iframe) because our monorepo project is based on different frontend framework and it spends least time to implement. But we should handle CSP (Content Security Policy) additionally to prevent other website to use the preview page.