@ -0,0 +1,80 @@
|
|||||||
|
import { ImageUploadContent } from '@/components/ImageUploadContent'
|
||||||
|
import { TextInput } from '@/components/inputs'
|
||||||
|
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
|
||||||
|
import { Stack } from '@chakra-ui/react'
|
||||||
|
import { isDefined, isNotEmpty } from '@typebot.io/lib'
|
||||||
|
import { ImageBubbleBlock } from '@typebot.io/schemas'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
typebotId: string
|
||||||
|
block: ImageBubbleBlock
|
||||||
|
onContentChange: (content: ImageBubbleBlock['content']) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ImageBubbleSettings = ({
|
||||||
|
typebotId,
|
||||||
|
block,
|
||||||
|
onContentChange,
|
||||||
|
}: Props) => {
|
||||||
|
const [showClickLinkInput, setShowClickLinkInput] = useState(
|
||||||
|
isNotEmpty(block.content.clickLink?.url)
|
||||||
|
)
|
||||||
|
|
||||||
|
const updateImage = (url: string) => {
|
||||||
|
onContentChange({ ...block.content, url })
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateClickLinkUrl = (url: string) => {
|
||||||
|
onContentChange({
|
||||||
|
...block.content,
|
||||||
|
clickLink: { ...block.content.clickLink, url },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateClickLinkAltText = (alt: string) => {
|
||||||
|
onContentChange({
|
||||||
|
...block.content,
|
||||||
|
clickLink: { ...block.content.clickLink, alt },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleClickLink = () => {
|
||||||
|
if (isDefined(block.content.clickLink) && showClickLinkInput) {
|
||||||
|
onContentChange({ ...block.content, clickLink: undefined })
|
||||||
|
}
|
||||||
|
setShowClickLinkInput(!showClickLinkInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack p="2" spacing={4}>
|
||||||
|
<ImageUploadContent
|
||||||
|
filePath={`typebots/${typebotId}/blocks/${block.id}`}
|
||||||
|
defaultUrl={block.content?.url}
|
||||||
|
onSubmit={updateImage}
|
||||||
|
/>
|
||||||
|
<Stack>
|
||||||
|
<SwitchWithLabel
|
||||||
|
label={'On click link'}
|
||||||
|
initialValue={showClickLinkInput}
|
||||||
|
onCheckChange={toggleClickLink}
|
||||||
|
/>
|
||||||
|
{showClickLinkInput && (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
autoFocus
|
||||||
|
placeholder="https://example.com"
|
||||||
|
onChange={updateClickLinkUrl}
|
||||||
|
defaultValue={block.content.clickLink?.url}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder="Link alt text (description)"
|
||||||
|
onChange={updateClickLinkAltText}
|
||||||
|
defaultValue={block.content.clickLink?.alt}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { ImageUploadContent } from '@/components/ImageUploadContent'
|
|
||||||
import { AudioBubbleForm } from '@/features/blocks/bubbles/audio/components/AudioBubbleForm'
|
import { AudioBubbleForm } from '@/features/blocks/bubbles/audio/components/AudioBubbleForm'
|
||||||
import { EmbedUploadContent } from '@/features/blocks/bubbles/embed/components/EmbedUploadContent'
|
import { EmbedUploadContent } from '@/features/blocks/bubbles/embed/components/EmbedUploadContent'
|
||||||
|
import { ImageBubbleSettings } from '@/features/blocks/bubbles/image/components/ImageBubbleSettings'
|
||||||
import { VideoUploadContent } from '@/features/blocks/bubbles/video/components/VideoUploadContent'
|
import { VideoUploadContent } from '@/features/blocks/bubbles/video/components/VideoUploadContent'
|
||||||
import {
|
import {
|
||||||
Portal,
|
Portal,
|
||||||
@ -46,15 +46,13 @@ export const MediaBubbleContent = ({
|
|||||||
block,
|
block,
|
||||||
onContentChange,
|
onContentChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const handleImageUrlChange = (url: string) => onContentChange({ url })
|
|
||||||
|
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
case BubbleBlockType.IMAGE: {
|
case BubbleBlockType.IMAGE: {
|
||||||
return (
|
return (
|
||||||
<ImageUploadContent
|
<ImageBubbleSettings
|
||||||
filePath={`typebots/${typebotId}/blocks/${block.id}`}
|
typebotId={typebotId}
|
||||||
defaultUrl={block.content?.url}
|
block={block}
|
||||||
onSubmit={handleImageUrlChange}
|
onContentChange={onContentChange}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@typebot.io/js",
|
"name": "@typebot.io/js",
|
||||||
"version": "0.0.33",
|
"version": "0.0.34",
|
||||||
"description": "Javascript library to display typebots on your website",
|
"description": "Javascript library to display typebots on your website",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
@ -37,7 +37,7 @@ export const HostBubble = (props: Props) => {
|
|||||||
</Match>
|
</Match>
|
||||||
<Match when={props.message.type === BubbleBlockType.IMAGE}>
|
<Match when={props.message.type === BubbleBlockType.IMAGE}>
|
||||||
<ImageBubble
|
<ImageBubble
|
||||||
url={(props.message.content as ImageBubbleContent).url}
|
content={props.message.content as ImageBubbleContent}
|
||||||
onTransitionEnd={onTransitionEnd}
|
onTransitionEnd={onTransitionEnd}
|
||||||
/>
|
/>
|
||||||
</Match>
|
</Match>
|
||||||
|
@ -3,7 +3,7 @@ import type { ImageBubbleContent } from '@typebot.io/schemas'
|
|||||||
import { createSignal, onCleanup, onMount } from 'solid-js'
|
import { createSignal, onCleanup, onMount } from 'solid-js'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
url: ImageBubbleContent['url']
|
content: ImageBubbleContent
|
||||||
onTransitionEnd: () => void
|
onTransitionEnd: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +38,21 @@ export const ImageBubble = (props: Props) => {
|
|||||||
if (typingTimeout) clearTimeout(typingTimeout)
|
if (typingTimeout) clearTimeout(typingTimeout)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const Image = (
|
||||||
|
<img
|
||||||
|
ref={image}
|
||||||
|
src={props.content.url}
|
||||||
|
alt={props.content.clickLink?.alt ?? 'Bubble image'}
|
||||||
|
class={
|
||||||
|
'text-fade-in w-full ' + (isTyping() ? 'opacity-0' : 'opacity-100')
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
'max-height': '512px',
|
||||||
|
height: isTyping() ? '32px' : 'auto',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex flex-col animate-fade-in">
|
<div class="flex flex-col animate-fade-in">
|
||||||
<div class="flex mb-2 w-full items-center">
|
<div class="flex mb-2 w-full items-center">
|
||||||
@ -51,21 +66,17 @@ export const ImageBubble = (props: Props) => {
|
|||||||
>
|
>
|
||||||
{isTyping() ? <TypingBubble /> : null}
|
{isTyping() ? <TypingBubble /> : null}
|
||||||
</div>
|
</div>
|
||||||
<figure class="p-4 z-10">
|
{props.content.clickLink ? (
|
||||||
<img
|
<a
|
||||||
ref={image}
|
href={props.content.clickLink.url}
|
||||||
src={props.url}
|
target="_blank"
|
||||||
class={
|
class="p-4 z-10"
|
||||||
'text-fade-in w-full ' +
|
>
|
||||||
(isTyping() ? 'opacity-0' : 'opacity-100')
|
{Image}
|
||||||
}
|
</a>
|
||||||
style={{
|
) : (
|
||||||
'max-height': '512px',
|
<figure class="p-4 z-10">{Image}</figure>
|
||||||
height: isTyping() ? '32px' : 'auto',
|
)}
|
||||||
}}
|
|
||||||
alt="Bubble image"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@typebot.io/react",
|
"name": "@typebot.io/react",
|
||||||
"version": "0.0.33",
|
"version": "0.0.34",
|
||||||
"description": "React library to display typebots on your website",
|
"description": "React library to display typebots on your website",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
@ -4,6 +4,12 @@ import { BubbleBlockType } from './enums'
|
|||||||
|
|
||||||
export const imageBubbleContentSchema = z.object({
|
export const imageBubbleContentSchema = z.object({
|
||||||
url: z.string().optional(),
|
url: z.string().optional(),
|
||||||
|
clickLink: z
|
||||||
|
.object({
|
||||||
|
url: z.string().optional(),
|
||||||
|
alt: z.string().optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const imageBubbleBlockSchema = blockBaseSchema.merge(
|
export const imageBubbleBlockSchema = blockBaseSchema.merge(
|
||||||
|
Reference in New Issue
Block a user