Skip to content

Commit

Permalink
✨ (theme) Add progress bar option (#1276)
Browse files Browse the repository at this point in the history
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced progress bar functionality across various components for a
more interactive user experience.
	- Added progress tracking and display in chat sessions.
- **Enhancements**
- Adjusted layout height calculations in the settings and theme pages
for consistency.
- Improved theme customization options with progress bar styling and
placement settings.
- **Bug Fixes**
- Fixed dynamic height calculation issues in settings and theme side
menus by standardizing heights.
- **Style**
- Added custom styling properties for the progress bar in chat
interfaces.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
baptisteArno committed Feb 23, 2024
1 parent f2b2174 commit 2d7ccf1
Show file tree
Hide file tree
Showing 30 changed files with 535 additions and 90 deletions.
19 changes: 12 additions & 7 deletions apps/builder/src/components/ColorPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import {
Box,
} from '@chakra-ui/react'
import { useTranslate } from '@tolgee/react'
import React, { ChangeEvent, useState } from 'react'
import React, { useState } from 'react'
import tinyColor from 'tinycolor2'
import { useDebouncedCallback } from 'use-debounce'

const colorsSelection: `#${string}`[] = [
'#666460',
Expand All @@ -42,9 +43,9 @@ export const ColorPicker = ({ value, defaultValue, onColorChange }: Props) => {
const [color, setColor] = useState(defaultValue ?? '')
const displayedValue = value ?? color

const handleColorChange = (e: ChangeEvent<HTMLInputElement>) => {
setColor(e.target.value)
onColorChange(e.target.value)
const handleColorChange = (color: string) => {
setColor(color)
onColorChange(color)
}

const handleClick = (color: string) => () => {
Expand Down Expand Up @@ -103,7 +104,7 @@ export const ColorPicker = ({ value, defaultValue, onColorChange }: Props) => {
aria-label={t('colorPicker.colorValue.ariaLabel')}
size="sm"
value={displayedValue}
onChange={handleColorChange}
onChange={(e) => handleColorChange(e.target.value)}
/>
<NativeColorPicker
size="sm"
Expand All @@ -124,8 +125,12 @@ const NativeColorPicker = ({
...props
}: {
color: string
onColorChange: (e: ChangeEvent<HTMLInputElement>) => void
onColorChange: (color: string) => void
} & ButtonProps) => {
const debouncedOnColorChange = useDebouncedCallback((color: string) => {
onColorChange(color)
}, 200)

return (
<>
<Button as="label" htmlFor="native-picker" {...props}>
Expand All @@ -136,7 +141,7 @@ const NativeColorPicker = ({
display="none"
id="native-picker"
value={color}
onChange={onColorChange}
onChange={(e) => debouncedOnColorChange(e.target.value)}
/>
</>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { TypebotHeader } from '@/features/editor/components/TypebotHeader'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { TypebotNotFoundPage } from '@/features/editor/components/TypebotNotFoundPage'
import { env } from '@typebot.io/env'
import { headerHeight } from '@/features/editor/constants'

export const SettingsPage = () => {
const { typebot, is404 } = useTypebot()
Expand All @@ -15,7 +16,7 @@ export const SettingsPage = () => {
<Flex overflow="hidden" h="100vh" flexDir="column">
<Seo title={typebot?.name ? `${typebot.name} | Settings` : 'Settings'} />
<TypebotHeader />
<Flex h="full" w="full">
<Flex height={`calc(100vh - ${headerHeight}px)`} w="full">
<SettingsSideMenu />
<Flex flex="1">
{typebot && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { GeneralSettingsForm } from './GeneralSettingsForm'
import { MetadataForm } from './MetadataForm'
import { TypingEmulationForm } from './TypingEmulationForm'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { headerHeight } from '@/features/editor/constants'
import { SecurityForm } from './SecurityForm'

export const SettingsSideMenu = () => {
Expand Down Expand Up @@ -52,7 +51,7 @@ export const SettingsSideMenu = () => {
<Stack
flex="1"
maxW="400px"
height={`calc(100vh - ${headerHeight}px)`}
height="full"
borderRightWidth={1}
pt={10}
spacing={10}
Expand Down
3 changes: 2 additions & 1 deletion apps/builder/src/features/theme/components/ThemePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Flex } from '@chakra-ui/react'
import { Standard } from '@typebot.io/nextjs'
import { ThemeSideMenu } from './ThemeSideMenu'
import { TypebotNotFoundPage } from '@/features/editor/components/TypebotNotFoundPage'
import { headerHeight } from '@/features/editor/constants'

export const ThemePage = () => {
const { typebot, is404 } = useTypebot()
Expand All @@ -14,7 +15,7 @@ export const ThemePage = () => {
<Flex overflow="hidden" h="100vh" flexDir="column">
<Seo title={typebot?.name ? `${typebot.name} | Theme` : 'Theme'} />
<TypebotHeader />
<Flex h="full" w="full">
<Flex w="full" height={`calc(100vh - ${headerHeight}px)`}>
<ThemeSideMenu />
<Flex flex="1">
{typebot && (
Expand Down
3 changes: 1 addition & 2 deletions apps/builder/src/features/theme/components/ThemeSideMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { ChatTheme, GeneralTheme, ThemeTemplate } from '@typebot.io/schemas'
import React from 'react'
import { CustomCssSettings } from './CustomCssSettings'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { headerHeight } from '@/features/editor/constants'
import { ChatThemeSettings } from './chat/ChatThemeSettings'
import { GeneralSettings } from './general/GeneralSettings'
import { ThemeTemplates } from './ThemeTemplates'
Expand Down Expand Up @@ -61,7 +60,7 @@ export const ThemeSideMenu = () => {
<Stack
flex="1"
maxW="400px"
height={`calc(100vh - ${headerHeight}px)`}
h="full"
borderRightWidth={1}
pt={10}
spacing={10}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,56 +34,61 @@ export const BackgroundContent = ({
const handleContentChange = (content: string) =>
onBackgroundContentChange(content)

switch (background?.type) {
case BackgroundType.COLOR:
return (
<Flex justify="space-between" align="center">
<Text>{t('theme.sideMenu.global.background.color')}</Text>
<ColorPicker
value={
background.content ?? defaultTheme.general.background.content
}
onColorChange={handleContentChange}
/>
</Flex>
)
case BackgroundType.IMAGE:
if (!typebot) return null
return (
<Popover isLazy placement="top">
<PopoverTrigger>
{isNotEmpty(background.content) ? (
<Image
src={background.content}
alt={t('theme.sideMenu.global.background.image.alt')}
cursor="pointer"
_hover={{ filter: 'brightness(.9)' }}
transition="filter 200ms"
rounded="md"
maxH="200px"
objectFit="cover"
/>
) : (
<Button>
{t('theme.sideMenu.global.background.image.button')}
</Button>
)}
</PopoverTrigger>
<Portal>
<PopoverContent p="4" w="500px">
<ImageUploadContent
uploadFileProps={{
workspaceId: typebot.workspaceId,
typebotId: typebot.id,
fileName: 'background',
}}
defaultUrl={background.content}
onSubmit={handleContentChange}
excludedTabs={['giphy', 'icon']}
/>
</PopoverContent>
</Portal>
</Popover>
)
if (
(background?.type ?? defaultTheme.general.background.type) ===
BackgroundType.IMAGE
) {
if (!typebot) return null
return (
<Popover isLazy placement="top">
<PopoverTrigger>
{isNotEmpty(background?.content) ? (
<Image
src={background?.content}
alt={t('theme.sideMenu.global.background.image.alt')}
cursor="pointer"
_hover={{ filter: 'brightness(.9)' }}
transition="filter 200ms"
rounded="md"
maxH="200px"
objectFit="cover"
/>
) : (
<Button>
{t('theme.sideMenu.global.background.image.button')}
</Button>
)}
</PopoverTrigger>
<Portal>
<PopoverContent p="4" w="500px">
<ImageUploadContent
uploadFileProps={{
workspaceId: typebot.workspaceId,
typebotId: typebot.id,
fileName: 'background',
}}
defaultUrl={background?.content}
onSubmit={handleContentChange}
excludedTabs={['giphy', 'icon']}
/>
</PopoverContent>
</Portal>
</Popover>
)
}
if (
(background?.type ?? defaultTheme.general.background.type) ===
BackgroundType.COLOR
) {
return (
<Flex justify="space-between" align="center">
<Text>{t('theme.sideMenu.global.background.color')}</Text>
<ColorPicker
value={background?.content ?? defaultTheme.general.background.content}
onColorChange={handleContentChange}
/>
</Flex>
)
}
return null
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@ import { Stack, Text } from '@chakra-ui/react'
import { Background } from '@typebot.io/schemas'
import React from 'react'
import { BackgroundContent } from './BackgroundContent'
import { BackgroundType } from '@typebot.io/schemas/features/typebot/theme/constants'
import {
BackgroundType,
defaultTheme,
} from '@typebot.io/schemas/features/typebot/theme/constants'
import { useTranslate } from '@tolgee/react'

type Props = {
background?: Background
onBackgroundChange: (newBackground: Background) => void
}

const defaultBackgroundType = BackgroundType.NONE

export const BackgroundSelector = ({
background,
onBackgroundChange,
}: Props) => {
const { t } = useTranslate()

const handleBackgroundTypeChange = (type: BackgroundType) =>
background &&
onBackgroundChange({ ...background, type, content: undefined })

const handleBackgroundContentChange = (content: string) =>
background && onBackgroundChange({ ...background, content })
onBackgroundChange({ ...background, content })

return (
<Stack spacing={4}>
Expand All @@ -44,7 +44,7 @@ export const BackgroundSelector = ({
value: BackgroundType.NONE,
},
]}
value={background?.type ?? defaultBackgroundType}
value={background?.type ?? defaultTheme.general.background.type}
onSelect={handleBackgroundTypeChange}
/>
<BackgroundContent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { GoogleFontForm } from './GoogleFontForm'
import { CustomFontForm } from './CustomFontForm'

type Props = {
font: Font
font: Font | undefined
onFontChange: (font: Font) => void
}

export const FontForm = ({ font, onFontChange }: Props) => {
if (typeof font === 'string' || font.type === 'Google')
if (!font || typeof font === 'string' || font?.type === 'Google')
return <GoogleFontForm font={font} onFontChange={onFontChange} />
if (font.type === 'Custom')
return <CustomFontForm font={font} onFontChange={onFontChange} />
return null
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
useDisclosure,
Text,
} from '@chakra-ui/react'
import { Background, Font, Theme } from '@typebot.io/schemas'
import { Background, Font, ProgressBar, Theme } from '@typebot.io/schemas'
import React from 'react'
import { BackgroundSelector } from './BackgroundSelector'
import { LockTag } from '@/features/billing/components/LockTag'
Expand All @@ -24,6 +24,7 @@ import { env } from '@typebot.io/env'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { RadioButtons } from '@/components/inputs/RadioButtons'
import { FontForm } from './FontForm'
import { ProgressBarForm } from './ProgressBarForm'

type Props = {
isBrandingEnabled: boolean
Expand Down Expand Up @@ -63,6 +64,9 @@ export const GeneralSettings = ({
const handleBackgroundChange = (background: Background) =>
onGeneralThemeChange({ ...generalTheme, background })

const updateProgressBar = (progressBar: ProgressBar) =>
onGeneralThemeChange({ ...generalTheme, progressBar })

const updateBranding = () => {
if (isBrandingEnabled && isWorkspaceFreePlan) return
if (
Expand Down Expand Up @@ -118,15 +122,16 @@ export const GeneralSettings = ({
defaultValue={fontType}
onSelect={updateFontType}
/>
<FontForm
font={generalTheme?.font ?? defaultTheme.general.font}
onFontChange={updateFont}
/>
<FontForm font={generalTheme?.font} onFontChange={updateFont} />
</Stack>
<BackgroundSelector
background={generalTheme?.background ?? defaultTheme.general.background}
background={generalTheme?.background}
onBackgroundChange={handleBackgroundChange}
/>
<ProgressBarForm
progressBar={generalTheme?.progressBar}
onProgressBarChange={updateProgressBar}
/>
</Stack>
)
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { Select } from '@/components/inputs/Select'
import { env } from '@typebot.io/env'
import { GoogleFont } from '@typebot.io/schemas'
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
import { useState, useEffect } from 'react'

type Props = {
font: GoogleFont | string
font: GoogleFont | string | undefined
onFontChange: (font: GoogleFont) => void
}

export const GoogleFontForm = ({ font, onFontChange }: Props) => {
const [currentFont, setCurrentFont] = useState(
typeof font === 'string' ? font : font.family
(typeof font === 'string' ? font : font?.family) ??
defaultTheme.general.font.family
)
const [googleFonts, setGoogleFonts] = useState<string[]>([])

Expand Down

0 comments on commit 2d7ccf1

Please sign in to comment.