Skip to content

Commit

Permalink
💄 (buttons) Improve multiple choice form UI
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Apr 26, 2023
1 parent f51d619 commit 124f350
Show file tree
Hide file tree
Showing 33 changed files with 454 additions and 262 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ test.describe.parallel('Buttons input block', () => {
await expect(page.locator('text=Item 2')).toBeHidden()

await page.click('text=Preview')
const item3Button = page.locator('button >> text=Item 3')
await item3Button.click()
await expect(item3Button).toBeHidden()
await page.getByRole('button', { name: 'Item 3' }).click()
await expect(page.getByRole('button', { name: 'Item 3' })).toBeHidden()
await expect(page.getByTestId('guest-bubble')).toHaveText('Item 3')
await page.click('button[aria-label="Close"]')

Expand All @@ -67,8 +66,8 @@ test.describe.parallel('Buttons input block', () => {

await page.click('text=Preview')

await page.locator('button >> text="Item 3"').click()
await page.locator('button >> text="Item 1"').click()
await page.getByRole('checkbox', { name: 'Item 3' }).click()
await page.getByRole('checkbox', { name: 'Item 1' }).click()
await page.locator('text=Go').click()

await expect(page.locator('text="Item 3, Item 1"')).toBeVisible()
Expand Down
14 changes: 7 additions & 7 deletions apps/builder/src/features/theme/theme.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ test.describe.parallel('Theme page', () => {
id: typebotId,
})
await page.goto(`/typebots/${typebotId}/theme`)
await expect(page.locator('button >> text="Go"')).toBeVisible()
await expect(page.getByRole('button', { name: 'Go' })).toBeVisible()

// Font
await page.getByRole('button', { name: 'Font & Background' }).click()
Expand Down Expand Up @@ -70,7 +70,7 @@ test.describe.parallel('Theme page', () => {
}

await page.goto(`/typebots/${typebotId}/theme`)
await expect(page.locator('button >> text="Go"')).toBeVisible()
await expect(page.getByRole('button', { name: 'Go' })).toBeVisible()
await page.click('button:has-text("Chat")')

// Host avatar
Expand All @@ -81,7 +81,7 @@ test.describe.parallel('Theme page', () => {
'input[placeholder="Paste the image link..."]',
hostAvatarUrl
)
await page.locator('button >> text="Go"').click()
await page.getByRole('button', { name: 'Go' }).click()

await expect(page.locator('.typebot-container img')).toHaveAttribute(
'src',
Expand Down Expand Up @@ -155,7 +155,7 @@ test.describe.parallel('Theme page', () => {
'[data-testid="guest-bubbles-theme"] >> [aria-label="Pick a color"] >> nth=1'
)
await page.fill('input[value="#FFFFFF"]', '#264653')
await page.locator('button >> text="Go"').click()
await page.getByRole('button', { name: 'Go' }).click()
const guestBubble = page.locator('[data-testid="guest-bubble"] >> nth=-1')
await expect(guestBubble).toHaveCSS(
'background-color',
Expand All @@ -173,7 +173,7 @@ test.describe.parallel('Theme page', () => {
await page
.locator('input[placeholder="Paste the image link..."]')
.fill(guestAvatarUrl)
await page.locator('button >> text="Go"').click()
await page.getByRole('button', { name: 'Go' }).click()
await expect(page.locator('.typebot-container img')).toHaveAttribute(
'src',
guestAvatarUrl
Expand Down Expand Up @@ -202,7 +202,7 @@ test.describe.parallel('Theme page', () => {
id: typebotId,
})
await page.goto(`/typebots/${typebotId}/theme`)
await expect(page.locator('button >> text="Go"')).toBeVisible()
await expect(page.getByRole('button', { name: 'Go' })).toBeVisible()
await page.click('button:has-text("Custom CSS")')
await page.fill(
'div[role="textbox"]',
Expand All @@ -222,7 +222,7 @@ test.describe.parallel('Theme page', () => {
id: typebotId,
})
await page.goto(`/typebots/${typebotId}/theme`)
await expect(page.locator('button >> text="Go"')).toBeVisible()
await expect(page.getByRole('button', { name: 'Go' })).toBeVisible()
await page.getByRole('button', { name: 'Templates New!' }).click()
await page.getByRole('button', { name: 'Save current theme' }).click()
await page.getByPlaceholder('My template').fill('My awesome theme')
Expand Down
2 changes: 1 addition & 1 deletion apps/viewer/src/features/results/results.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test('Big groups should work as expected', async ({ page }) => {
await page.locator('input').press('Enter')
await page.locator('input').fill('26')
await page.locator('input').press('Enter')
await page.locator('button >> text=Yes').click()
await page.getByRole('button', { name: 'Yes' }).click()
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await expect(page.locator('text="Baptiste"')).toBeVisible()
await expect(page.locator('text="26"')).toBeVisible()
Expand Down
2 changes: 1 addition & 1 deletion packages/embeds/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@typebot.io/js",
"version": "0.0.39",
"version": "0.0.40",
"description": "Javascript library to display typebots on your website",
"type": "module",
"main": "dist/index.js",
Expand Down
38 changes: 38 additions & 0 deletions packages/embeds/js/src/assets/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
--typebot-container-bg-image: none;
--typebot-container-bg-color: transparent;
--typebot-container-font-family: 'Open Sans';
--typebot-container-color: #303235;

--typebot-button-bg-color: #0042da;
--typebot-button-bg-color-rgb: 0, 66, 218;
--typebot-button-color: #ffffff;

--typebot-checkbox-bg-color: #ffffff;

--typebot-host-bubble-bg-color: #f7f8ff;
--typebot-host-bubble-color: #303235;

Expand Down Expand Up @@ -134,6 +138,7 @@ textarea {
background-color: var(--typebot-button-bg-color);
border: 1px solid var(--typebot-button-bg-color);
border-radius: var(--typebot-border-radius);
transition: all 0.3s ease;
}

.typebot-button.selectable {
Expand All @@ -142,6 +147,38 @@ textarea {
border: 1px solid var(--typebot-button-bg-color);
}

.typebot-selectable {
border: 1px solid rgba(var(--typebot-button-bg-color-rgb), 0.25);
border-radius: var(--typebot-border-radius);
color: var(--typebot-container-color);
background-color: rgba(var(--typebot-button-bg-color-rgb), 0.08);
transition: all 0.3s ease;
}

.typebot-selectable:hover {
background-color: rgba(var(--typebot-button-bg-color-rgb), 0.12);
border-color: rgba(var(--typebot-button-bg-color-rgb), 0.3);
}

.typebot-selectable.selected {
background-color: rgba(var(--typebot-button-bg-color-rgb), 0.18);
border-color: rgba(var(--typebot-button-bg-color-rgb), 0.35);
}

.typebot-checkbox {
border: 1px solid var(--typebot-button-bg-color);
border-radius: var(--typebot-border-radius);
background-color: var(--typebot-checkbox-bg-color);
color: var(--typebot-button-color);
padding: 1px;
border-radius: 2px;
transition: all 0.3s ease;
}

.typebot-checkbox.checked {
background-color: var(--typebot-button-bg-color);
}

.typebot-host-bubble {
color: var(--typebot-host-bubble-color);
}
Expand Down Expand Up @@ -220,6 +257,7 @@ textarea {

.typebot-upload-input {
transition: border-color 100ms ease-out;
border-radius: var(--typebot-border-radius);
}

.typebot-upload-input.dragging-over {
Expand Down
33 changes: 33 additions & 0 deletions packages/embeds/js/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { children, JSX, Show, splitProps } from 'solid-js'
import { Spinner } from './Spinner'

type Props = {
variant?: 'primary' | 'secondary'
children: JSX.Element
isDisabled?: boolean
isLoading?: boolean
} & JSX.ButtonHTMLAttributes<HTMLButtonElement>

export const Button = (props: Props) => {
const childrenReturn = children(() => props.children)
const [local, buttonProps] = splitProps(props, ['disabled', 'class'])

return (
<button
{...buttonProps}
disabled={props.isDisabled || props.isLoading}
class={
'py-2 px-4 font-semibold focus:outline-none filter hover:brightness-90 active:brightness-75 disabled:opacity-50 disabled:cursor-not-allowed disabled:brightness-100' +
(props.variant === 'secondary'
? ' secondary-button'
: ' typebot-button') +
' ' +
local.class
}
>
<Show when={!props.isLoading} fallback={<Spinner />}>
{childrenReturn()}
</Show>
</button>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ export const AvatarSideContainer = (props: Props) => {
<div
ref={avatarContainer}
class={
'flex mr-2 mb-2 flex-shrink-0 items-center relative typebot-avatar-container ' +
'flex flex-shrink-0 items-center relative typebot-avatar-container ' +
(isMobile() ? 'w-6' : 'w-10')
}
>
<div
class={
'absolute mb-2 flex items-center top-0' +
'absolute flex items-center top-0' +
(isMobile() ? ' w-6 h-6' : ' w-10 h-10') +
(props.hideAvatar ? ' opacity-0' : ' opacity-100')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,57 +46,54 @@ export const ChatChunk = (props: Props) => {
}

return (
<div class="flex w-full">
<div class="flex flex-col w-full min-w-0">
<div class="flex">
<Show
when={
props.theme.chat.hostAvatar?.isEnabled &&
props.messages.length > 0
}
>
<AvatarSideContainer
hostAvatarSrc={props.theme.chat.hostAvatar?.url}
hideAvatar={props.hideAvatar}
/>
</Show>
<div
class="flex-1"
style={{
'margin-right': props.theme.chat.guestAvatar?.isEnabled
? isMobile()
? '32px'
: '48px'
: undefined,
}}
>
<For each={props.messages.slice(0, displayedMessageIndex() + 1)}>
{(message) => (
<HostBubble
message={message}
typingEmulation={props.settings.typingEmulation}
onTransitionEnd={displayNextMessage}
/>
)}
</For>
</div>
</div>
{props.input && displayedMessageIndex() === props.messages.length && (
<InputChatBlock
block={props.input}
inputIndex={props.inputIndex}
onSubmit={props.onSubmit}
onSkip={props.onSkip}
hasHostAvatar={props.theme.chat.hostAvatar?.isEnabled ?? false}
guestAvatar={props.theme.chat.guestAvatar}
context={props.context}
isInputPrefillEnabled={
props.settings.general.isInputPrefillEnabled ?? true
}
hasError={props.hasError}
<div class="flex flex-col w-full min-w-0 gap-2">
<div class={'flex' + (isMobile() ? ' gap-1' : ' gap-2')}>
<Show
when={
props.theme.chat.hostAvatar?.isEnabled && props.messages.length > 0
}
>
<AvatarSideContainer
hostAvatarSrc={props.theme.chat.hostAvatar?.url}
hideAvatar={props.hideAvatar}
/>
)}
</Show>
<div
class="flex flex-col flex-1 gap-2"
style={{
'margin-right': props.theme.chat.guestAvatar?.isEnabled
? isMobile()
? '32px'
: '48px'
: undefined,
}}
>
<For each={props.messages.slice(0, displayedMessageIndex() + 1)}>
{(message) => (
<HostBubble
message={message}
typingEmulation={props.settings.typingEmulation}
onTransitionEnd={displayNextMessage}
/>
)}
</For>
</div>
</div>
{props.input && displayedMessageIndex() === props.messages.length && (
<InputChatBlock
block={props.input}
inputIndex={props.inputIndex}
onSubmit={props.onSubmit}
onSkip={props.onSkip}
hasHostAvatar={props.theme.chat.hostAvatar?.isEnabled ?? false}
guestAvatar={props.theme.chat.guestAvatar}
context={props.context}
isInputPrefillEnabled={
props.settings.general.isInputPrefillEnabled ?? true
}
hasError={props.hasError}
/>
)}
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export const ConversationContainer = (props: Props) => {
return (
<div
ref={chatContainer}
class="overflow-y-scroll w-full min-h-full px-3 pt-10 relative scrollable-container typebot-chat-view scroll-smooth"
class="flex flex-col overflow-y-scroll w-full min-h-full px-3 pt-10 relative scrollable-container typebot-chat-view scroll-smooth gap-2"
>
<For each={chatChunks()}>
{(chatChunk, index) => (
Expand Down Expand Up @@ -228,5 +228,5 @@ type BottomSpacerProps = {
ref: HTMLDivElement | undefined
}
const BottomSpacer = (props: BottomSpacerProps) => {
return <div ref={props.ref} class="w-full h-32" />
return <div ref={props.ref} class="w-full h-32 flex-shrink-0" />
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ export const PopupBlockedToast = (props: Props) => {
class="w-full max-w-xs p-4 text-gray-500 bg-white shadow flex flex-col gap-2 typebot-popup-blocked-toast"
role="alert"
>
<span class="mb-1 text-sm font-semibold text-gray-900">
Popup blocked
</span>
<div class="mb-2 text-sm font-normal">
The bot wants to open a new tab but it was blocked by your broswer. It
needs a manual approval.
<div class="flex flex-col gap-1">
<span class=" text-sm font-semibold text-gray-900">Popup blocked</span>
<div class="text-sm font-normal">
The bot wants to open a new tab but it was blocked by your broswer. It
needs a manual approval.
</div>
</div>

<a
href={props.url}
target="_blank"
class="py-1 px-4 justify-center text-sm font-semibold text-white focus:outline-none flex items-center disabled:opacity-50 disabled:cursor-not-allowed disabled:brightness-100 transition-all filter hover:brightness-90 active:brightness-75 typebot-button"
class="py-1 px-4 justify-center text-sm font-semibold text-white focus:outline-none flex items-center disabled:opacity-50 disabled:cursor-not-allowed disabled:brightness-100 filter hover:brightness-90 active:brightness-75 typebot-button"
rel="noreferrer"
onClick={() => props.onLinkClick()}
>
Expand Down
Loading

4 comments on commit 124f350

@vercel
Copy link

@vercel vercel bot commented on 124f350 Apr 26, 2023

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-git-main-typebot-io.vercel.app
docs-typebot-io.vercel.app
docs.typebot.io

@vercel
Copy link

@vercel vercel bot commented on 124f350 Apr 26, 2023

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

bii.bj
1stop.au
yobot.me
klujo.com
me.cr8.ai
wachat.io
wassep.io
247987.com
typebot.aloe.do
bot.contakit.com
bot.piccinato.co
bot.sv-energy.it
botc.ceox.com.br
clo.closeer.work
cockroach.cr8.ai
faqs.nigerias.io
form.syncwin.com
haymanevents.com
kw.wpwakanda.com
myrentalhost.com
stan.vselise.com
start.taxtree.io
typebot.aloe.bot
voicehelp.cr8.ai
zap.fundviser.in
app.bouclidom.com
app.chatforms.net
bot.hostnation.de
bot.maitempah.com
bot.phuonghub.com
bot.reviewzer.com
bot.rihabilita.it
cares.urlabout.me
chat.gaswadern.de
chat.rojie.online
fmm.wpwakanda.com
footballmeetup.ie
gentleman-shop.fr
k1.kandabrand.com
kp.pedroknoll.com
lb.ticketfute.com
ov1.wpwakanda.com
ov2.wpwakanda.com
ov3.wpwakanda.com
support.triplo.ai
viewer.typebot.io
welcome.triplo.ai
1988.bouclidom.com
andreimayer.com.br
bot.danyservice.it
bot.iconicbrows.it
bot.lucide.contact
bot.megafox.com.br
bot.neferlopez.com
bots.robomotion.io
cadu.uninta.edu.br
chat.tuanpakya.com
type.dericsoncalari.com.br
bot.pinpointinteractive.com
bot.polychromes-project.com
bot.seidinembroseanchetu.it
chat.semanalimpanome.com.br
designguide.techyscouts.com
liveconvert2.kandalearn.com
presente.empresarias.com.mx
register.algorithmpress.com
sell.sellthemotorhome.co.uk
anamnese.odontopavani.com.br
austin.channelautomation.com
bot.marketingplusmindset.com
bot.seidibergamoseanchetu.it
desabafe.sergiolimajr.com.br
download.venturemarketing.in
piazzatorre.barrettamario.it
type.cookieacademyonline.com
upload.atlasoutfittersk9.com
bot.brigadeirosemdrama.com.br
forms.escoladeautomacao.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
viewer-v2-typebot-io.vercel.app
yourfeedback.comebackreward.com
bot.cabin-rentals-of-georgia.net
gerador.verificadordehospedes.com
personal-trainer.barrettamario.it
preagendamento.sergiolimajr.com.br
studiotecnicoimmobiliaremerelli.it
download.thailandmicespecialist.com
register.thailandmicespecialist.com
bot.studiotecnicoimmobiliaremerelli.it
pesquisa.escolamodacomproposito.com.br
anamnese.clinicaramosodontologia.com.br
chrome-os-inquiry-system.itschromeos.com
viewer-v2-git-main-typebot-io.vercel.app
main-menu-for-itschromeos.itschromeos.com

@vercel
Copy link

@vercel vercel bot commented on 124f350 Apr 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 124f350 Apr 26, 2023

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

Please sign in to comment.