-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add Bubble and Popup in embed lib v2
Closes #214
- Loading branch information
1 parent
4bf93b4
commit 21f1c7a
Showing
38 changed files
with
1,586 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
export * from './components/TypebotViewer' | ||
export { parseVariables } from '@/features/variables' | ||
export * from 'util' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,9 @@ | ||
export * from '@prisma/client' | ||
|
||
// Named export for enums to avoid vite barrel export bug (https://github.com/nrwl/nx/issues/13704) | ||
export { | ||
Plan, | ||
WorkspaceRole, | ||
GraphNavigation, | ||
CollaborationType, | ||
} from '@prisma/client' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,139 @@ | ||
import styles from '../../../assets/index.css' | ||
import { createSignal } from 'solid-js' | ||
import { createSignal, onMount, Show, splitProps, onCleanup } from 'solid-js' | ||
import { Bot, BotProps } from '../../../components/Bot' | ||
import { CommandData } from '@/features/commands' | ||
import { BubbleButton } from './BubbleButton' | ||
import { PreviewMessage, PreviewMessageProps } from './PreviewMessage' | ||
import { isDefined } from 'utils' | ||
import { BubbleParams } from '../types' | ||
|
||
export type BubbleProps = BotProps & | ||
BubbleParams & { | ||
onOpen?: () => void | ||
onClose?: () => void | ||
onPreviewMessageClick?: () => void | ||
} | ||
|
||
export const Bubble = (props: BubbleProps) => { | ||
const [bubbleProps, botProps] = splitProps(props, [ | ||
'onOpen', | ||
'onClose', | ||
'previewMessage', | ||
'onPreviewMessageClick', | ||
'button', | ||
]) | ||
const [prefilledVariables, setPrefilledVariables] = createSignal( | ||
// eslint-disable-next-line solid/reactivity | ||
botProps.prefilledVariables | ||
) | ||
const [isPreviewMessageDisplayed, setIsPreviewMessageDisplayed] = | ||
createSignal(false) | ||
const [previewMessage, setPreviewMessage] = createSignal< | ||
Pick<PreviewMessageProps, 'avatarUrl' | 'message'> | ||
>({ | ||
message: bubbleProps.previewMessage?.message ?? '', | ||
avatarUrl: bubbleProps.previewMessage?.avatarUrl, | ||
}) | ||
|
||
export const Bubble = () => { | ||
const [isBotOpened, setIsBotOpened] = createSignal(false) | ||
const [isBotStarted, setIsBotStarted] = createSignal(false) | ||
|
||
onMount(() => { | ||
window.addEventListener('message', processIncomingEvent) | ||
const autoShowDelay = bubbleProps.previewMessage?.autoShowDelay | ||
if (isDefined(autoShowDelay)) { | ||
setTimeout(() => { | ||
showMessage() | ||
}, autoShowDelay) | ||
} | ||
}) | ||
|
||
onCleanup(() => { | ||
window.removeEventListener('message', processIncomingEvent) | ||
}) | ||
|
||
const processIncomingEvent = (event: MessageEvent<CommandData>) => { | ||
const { data } = event | ||
if (!data.isFromTypebot) return | ||
if (data.command === 'open') openBot() | ||
if (data.command === 'close') closeBot() | ||
if (data.command === 'toggle') toggleBot() | ||
if (data.command === 'showPreviewMessage') showMessage(data.message) | ||
if (data.command === 'hidePreviewMessage') hideMessage() | ||
if (data.command === 'setPrefilledVariables') | ||
setPrefilledVariables((existingPrefilledVariables) => ({ | ||
...existingPrefilledVariables, | ||
...data.variables, | ||
})) | ||
} | ||
|
||
const openBot = () => { | ||
if (!isBotStarted()) setIsBotStarted(true) | ||
hideMessage() | ||
setIsBotOpened(true) | ||
if (isBotOpened()) bubbleProps.onOpen?.() | ||
} | ||
|
||
const closeBot = () => { | ||
setIsBotOpened(false) | ||
if (isBotOpened()) bubbleProps.onClose?.() | ||
} | ||
|
||
const toggleBot = () => { | ||
setIsBotOpened(!isBotOpened()) | ||
isBotOpened() ? closeBot() : openBot() | ||
} | ||
|
||
const handlePreviewMessageClick = () => { | ||
bubbleProps.onPreviewMessageClick?.() | ||
openBot() | ||
} | ||
|
||
const showMessage = ( | ||
previewMessage?: Pick<PreviewMessageProps, 'avatarUrl' | 'message'> | ||
) => { | ||
if (previewMessage) setPreviewMessage(previewMessage) | ||
if (isBotOpened()) return | ||
setIsPreviewMessageDisplayed(true) | ||
} | ||
|
||
const hideMessage = () => { | ||
setIsPreviewMessageDisplayed(false) | ||
} | ||
|
||
return ( | ||
<> | ||
<style>{styles}</style> | ||
<button | ||
onClick={toggleBot} | ||
class="bg-blue-500 text-red-300 absolute bottom-4 right-4 w-12 h-12 rounded-full hover:scale-110 active:scale-95 transition-transform duration-200 flex justify-center items-center" | ||
> | ||
<svg | ||
viewBox="0 0 24 24" | ||
style={{ transition: 'transform 200ms, opacity 200ms' }} | ||
class={ | ||
'w-7 stroke-white stroke-2 fill-transparent absolute ' + | ||
(isBotOpened() ? 'scale-0 opacity-0' : 'scale-100 opacity-100') | ||
} | ||
> | ||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" /> | ||
</svg> | ||
<svg | ||
viewBox="0 0 24 24" | ||
style={{ transition: 'transform 200ms, opacity 200ms' }} | ||
class={ | ||
'w-7 fill-white absolute ' + | ||
(isBotOpened() | ||
? 'scale-100 rotate-0 opacity-100' | ||
: 'scale-0 -rotate-180 opacity-0') | ||
} | ||
> | ||
<path | ||
fill-rule="evenodd" | ||
clip-rule="evenodd" | ||
d="M18.601 8.39897C18.269 8.06702 17.7309 8.06702 17.3989 8.39897L12 13.7979L6.60099 8.39897C6.26904 8.06702 5.73086 8.06702 5.39891 8.39897C5.06696 8.73091 5.06696 9.2691 5.39891 9.60105L11.3989 15.601C11.7309 15.933 12.269 15.933 12.601 15.601L18.601 9.60105C18.9329 9.2691 18.9329 8.73091 18.601 8.39897Z" | ||
/> | ||
</svg> | ||
</button> | ||
<Show when={isPreviewMessageDisplayed()}> | ||
<PreviewMessage | ||
{...previewMessage()} | ||
button={bubbleProps.button} | ||
onClick={handlePreviewMessageClick} | ||
onCloseClick={hideMessage} | ||
/> | ||
</Show> | ||
<BubbleButton | ||
{...bubbleProps.button} | ||
toggleBot={toggleBot} | ||
isBotOpened={isBotOpened()} | ||
/> | ||
<div | ||
style={{ | ||
width: '400px', | ||
height: 'calc(100% - 104px)', | ||
'max-height': '704px', | ||
height: 'calc(100% - 80px)', | ||
transition: | ||
'transform 200ms cubic-bezier(0, 1.2, 1, 1), opacity 150ms ease-out', | ||
'transform-origin': 'bottom right', | ||
transform: isBotOpened() ? 'scale3d(1, 1, 1)' : 'scale3d(0, 0, 1)', | ||
'box-shadow': 'rgb(0 0 0 / 16%) 0px 5px 40px', | ||
}} | ||
class={ | ||
'absolute bottom-20 right-4 rounded-2xl ' + | ||
'absolute bottom-20 sm:right-4 rounded-lg bg-white w-full sm:w-[400px] max-h-[704px] ' + | ||
(isBotOpened() ? 'opacity-1' : 'opacity-0 pointer-events-none') | ||
} | ||
/> | ||
> | ||
<Show when={isBotStarted()}> | ||
<Bot {...botProps} prefilledVariables={prefilledVariables()} /> | ||
</Show> | ||
</div> | ||
</> | ||
) | ||
} |
67 changes: 67 additions & 0 deletions
67
packages/js/src/features/bubble/components/BubbleButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { Show } from 'solid-js' | ||
import { ButtonParams } from '../types' | ||
|
||
type Props = ButtonParams & { | ||
isBotOpened: boolean | ||
toggleBot: () => void | ||
} | ||
|
||
const defaultButtonColor = '#0042DA' | ||
|
||
export const BubbleButton = (props: Props) => { | ||
return ( | ||
<button | ||
// eslint-disable-next-line solid/reactivity | ||
onClick={props.toggleBot} | ||
class={ | ||
'absolute bottom-4 right-4 shadow-md w-12 h-12 rounded-full hover:scale-110 active:scale-95 transition-transform duration-200 flex justify-center items-center animate-fade-in' | ||
} | ||
style={{ | ||
'background-color': props.backgroundColor ?? defaultButtonColor, | ||
}} | ||
> | ||
<Show when={props.icon?.color} keyed> | ||
{(color) => ( | ||
<svg | ||
viewBox="0 0 24 24" | ||
style={{ | ||
stroke: color, | ||
}} | ||
class={ | ||
`w-7 stroke-2 fill-transparent absolute duration-200 transition ` + | ||
(props.isBotOpened | ||
? 'scale-0 opacity-0' | ||
: 'scale-100 opacity-100') | ||
} | ||
> | ||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" /> | ||
</svg> | ||
)} | ||
</Show> | ||
<Show when={props.icon?.url}> | ||
<img | ||
src={props.icon?.url} | ||
class="w-7 h-7 rounded-full object-cover" | ||
alt="Bubble button icon" | ||
/> | ||
</Show> | ||
|
||
<svg | ||
viewBox="0 0 24 24" | ||
style={{ fill: props.icon?.color ?? 'white' }} | ||
class={ | ||
`w-7 absolute duration-200 transition ` + | ||
(props.isBotOpened | ||
? 'scale-100 rotate-0 opacity-100' | ||
: 'scale-0 -rotate-180 opacity-0') | ||
} | ||
> | ||
<path | ||
fill-rule="evenodd" | ||
clip-rule="evenodd" | ||
d="M18.601 8.39897C18.269 8.06702 17.7309 8.06702 17.3989 8.39897L12 13.7979L6.60099 8.39897C6.26904 8.06702 5.73086 8.06702 5.39891 8.39897C5.06696 8.73091 5.06696 9.2691 5.39891 9.60105L11.3989 15.601C11.7309 15.933 12.269 15.933 12.601 15.601L18.601 9.60105C18.9329 9.2691 18.9329 8.73091 18.601 8.39897Z" | ||
/> | ||
</svg> | ||
</button> | ||
) | ||
} |
68 changes: 68 additions & 0 deletions
68
packages/js/src/features/bubble/components/PreviewMessage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { createSignal } from 'solid-js' | ||
import { BubbleParams, PreviewMessageParams } from '../types' | ||
|
||
export type PreviewMessageProps = Pick< | ||
PreviewMessageParams, | ||
'avatarUrl' | 'message' | 'style' | ||
> & | ||
Pick<BubbleParams, 'button'> & { | ||
onClick: () => void | ||
onCloseClick: () => void | ||
} | ||
|
||
const defaultFontFamily = | ||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'" | ||
|
||
export const PreviewMessage = (props: PreviewMessageProps) => { | ||
const [isPreviewMessageHovered, setIsPreviewMessageHovered] = | ||
createSignal(false) | ||
|
||
return ( | ||
<div | ||
// eslint-disable-next-line solid/reactivity | ||
onClick={props.onClick} | ||
class="absolute bottom-20 right-4 w-64 rounded-md duration-200 flex items-center gap-4 shadow-md animate-fade-in cursor-pointer hover:shadow-lg p-4" | ||
style={{ | ||
'font-family': props.style?.fontFamily ?? defaultFontFamily, | ||
'background-color': props.style?.backgroundColor ?? '#F7F8FF', | ||
color: props.style?.color ?? '#303235', | ||
}} | ||
onMouseEnter={() => setIsPreviewMessageHovered(true)} | ||
onMouseLeave={() => setIsPreviewMessageHovered(false)} | ||
> | ||
<button | ||
class={ | ||
`absolute -top-3 -right-3 rounded-full w-6 h-6 p-1 hover:brightness-95 active:brightness-90 transition-all ` + | ||
(isPreviewMessageHovered() ? 'opacity-100' : 'opacity-0') | ||
} | ||
onClick={(e) => { | ||
e.stopPropagation() | ||
return props.onCloseClick() | ||
}} | ||
style={{ | ||
'background-color': props.style?.closeButtonBgColor ?? '#F7F8FF', | ||
color: props.style?.closeButtonColor ?? '#303235', | ||
}} | ||
> | ||
<svg | ||
xmlns="http://www.w3.org/2000/svg" | ||
viewBox="0 0 24 24" | ||
fill="none" | ||
stroke="currentColor" | ||
stroke-width="2" | ||
stroke-linecap="round" | ||
stroke-linejoin="round" | ||
> | ||
<line x1="18" y1="6" x2="6" y2="18" /> | ||
<line x1="6" y1="6" x2="18" y2="18" /> | ||
</svg> | ||
</button> | ||
<img | ||
src={props.avatarUrl} | ||
class="rounded-full w-8 h-8 object-cover" | ||
alt="Bot avatar" | ||
/> | ||
<p>{props.message}</p> | ||
</div> | ||
) | ||
} |
Oops, something went wrong.
21f1c7a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
docs – ./apps/docs
docs.typebot.io
docs-git-main-typebot-io.vercel.app
docs-typebot-io.vercel.app
21f1c7a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
landing-page-v2 – ./apps/landing-page
landing-page-v2-typebot-io.vercel.app
landing-page-v2-git-main-typebot-io.vercel.app
get-typebot.com
typebot.io
www.typebot.io
www.get-typebot.com
21f1c7a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
viewer-v2 – ./apps/viewer
1stop.au
aginap.com
nepkit.com
bot.joof.it
bull.cr8.ai
cinecorn.com
snake.cr8.ai
yoda.riku.ai
bergamo.store
bot.tvbeat.it
app.yvon.earth
bots.bridge.ai
chat.hayuri.id
gollum.riku.ai
talk.gocare.io
bot.jesopizz.it
fitness.riku.ai
bot.contakit.com
zap.fundviser.in
bot.rihabilita.it
viewer.typebot.io
bot.danyservice.it
digitalhelp.com.au
bot.boston-voip.com
bot.dsignagency.com
chatbot.matthesv.de
demo.wemakebots.xyz
88584434.therpm.club
92109660.therpm.club
bot.barrettamario.it
hello.advergreen.com
bot.coachayongzul.com
bot.digitalpointer.id
bot.eikju.photography
bot.outstandbrand.com
bot.robertohairlab.it
criar.somaperuzzo.com
bot.ilmuseoaiborghi.it
bot.pratikmandalia.com
form.bridesquadapp.com
michaeljackson.riku.ai
87656003.actualizar.xyz
88152257.actualizar.xyz
91375310.actualizar.xyz
arrivalx2.wpwakanda.com
bot.hotelplayarimini.it
link.venturasuceder.com
manualhandlingcourse.ie
invite.bridesquadapp.com
bot.amicidisanfaustino.it
chat.thehomebuyersusa.com
forms.hiabhaykulkarni.com
healthandsafetycourses.uk
typebot-viewer.vercel.app
bot.adventureconsulting.hu
casestudyemb.wpwakanda.com
chat.atlasoutfittersk9.com
herbalife.barrettamario.it
homepageonly.wpwakanda.com
liveconvert.kandalearn.com
mainmenu1one.wpwakanda.com
tarian.theiofoundation.org
bot.pinpointinteractive.com
bot.polychromes-project.com
bot.seidinembroseanchetu.it
liveconvert2.kandalearn.com
bot.seidibergamoseanchetu.it
desabafe.sergiolimajr.com.br
forms.escoladeautomacao.com.br
viewer-v2-typebot-io.vercel.app
gerador.verificadordehospedes.com
bot.studiotecnicoimmobiliaremerelli.it
viewer-v2-git-main-typebot-io.vercel.app
21f1c7a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
builder-v2 – ./apps/builder
app.typebot.io
builder-v2-typebot-io.vercel.app
builder-v2-git-main-typebot-io.vercel.app
21f1c7a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
viewer-v2-alpha – ./apps/viewer
ns8.vn
yobot.me
247987.com
8jours.top
bee.cr8.ai
bot.aws.bj
bot.bbc.bj
cat.cr8.ai
finplex.be
pig.cr8.ai
sat.cr8.ai
bot.aipr.kr
docs.cr8.ai
minipost.uk
mole.cr8.ai
wolf.cr8.ai
bot.artiweb.app
bot.devitus.com
bot.tc-mail.com
chat.sureb4.com
eventhub.com.au
games.klujo.com
sakuranembro.it
typebot.aloe.do
bot.piccinato.co
bot.sv-energy.it
botc.ceox.com.br
clo.closeer.work
cockroach.cr8.ai
faqs.nigerias.io
feedback.ofx.one
form.syncwin.com
kw.wpwakanda.com
myrentalhost.com
stan.vselise.com
start.taxtree.io
typebot.aloe.bot
voicehelp.cr8.ai
app.chatforms.net
bot.agfunnel.tech
bot.hostnation.de
bot.maitempah.com
bot.phuonghub.com
bot.reviewzer.com
cares.urlabout.me
fmm.wpwakanda.com
gentleman-shop.fr
k1.kandabrand.com
lb.ticketfute.com
ov1.wpwakanda.com
ov2.wpwakanda.com
ov3.wpwakanda.com
1988.bouclidom.com
andreimayer.com.br
bot.megafox.com.br
bot.neferlopez.com
bots.robomotion.io
cadu.uninta.edu.br
dicanatural.online
goalsettingbot.com
bot.cabinrentalagency.com
bot.fusionstarreviews.com
boyfriend-breakup.riku.ai
brigadeirosemdrama.com.br
chat.ertcrebateportal.com
chat.thisiscrushhouse.com
sellmyharleylouisiana.com
verfica.botmachine.com.br
configurator.bouclidom.com
help.atlasoutfittersk9.com
ted.meujalecobrasil.com.br
type.dericsoncalari.com.br
chatbot.berbelanjabiz.trade
designguide.techyscouts.com
presente.empresarias.com.mx
sell.sellthemotorhome.co.uk
anamnese.odontopavani.com.br
austin.channelautomation.com
bot.marketingplusmindset.com
piazzatorre.barrettamario.it
requests.swamprecordsgnv.com
type.cookieacademyonline.com
bot.brigadeirosemdrama.com.br
onboarding.libertydreamcare.ie
type.talitasouzamarques.com.br
agendamento.sergiolimajr.com.br
anamnese.clinicamegasjdr.com.br
bookings.littlepartymonkeys.com
bot.comercializadoraomicron.com
elevateyourmind.groovepages.com
yourfeedback.comebackreward.com
personal-trainer.barrettamario.it
preagendamento.sergiolimajr.com.br
studiotecnicoimmobiliaremerelli.it
download.thailandmicespecialist.com
register.thailandmicespecialist.com
viewer-v2-alpha-typebot-io.vercel.app
pesquisa.escolamodacomproposito.com.br
anamnese.clinicaramosodontologia.com.br
viewer-v2-alpha-git-main-typebot-io.vercel.app