(theme) Add theme templates

Allows you to save your themes and select a theme from Typebot's gallery

Closes #275
This commit is contained in:
Baptiste Arnaud
2023-03-28 15:10:06 +02:00
parent c1cf817127
commit 38ed5758fe
49 changed files with 2066 additions and 116 deletions

View File

@@ -13,7 +13,7 @@ import {
Stack,
ButtonProps,
} from '@chakra-ui/react'
import React, { ChangeEvent, useEffect, useState } from 'react'
import React, { ChangeEvent, useState } from 'react'
import tinyColor from 'tinycolor2'
const colorsSelection: `#${string}`[] = [
@@ -29,31 +29,37 @@ const colorsSelection: `#${string}`[] = [
]
type Props = {
initialColor?: string
value?: string
defaultValue?: string
onColorChange: (color: string) => void
}
export const ColorPicker = ({ initialColor, onColorChange }: Props) => {
const [color, setColor] = useState(initialColor ?? '')
export const ColorPicker = ({ value, defaultValue, onColorChange }: Props) => {
const [color, setColor] = useState(defaultValue ?? '')
const displayedValue = value ?? color
useEffect(() => {
onColorChange(color)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [color])
const handleColorChange = (e: ChangeEvent<HTMLInputElement>) =>
const handleColorChange = (e: ChangeEvent<HTMLInputElement>) => {
setColor(e.target.value)
onColorChange(e.target.value)
}
const handleClick = (color: string) => () => setColor(color)
const handleClick = (color: string) => () => {
setColor(color)
onColorChange(color)
}
return (
<Popover variant="picker" placement="right" isLazy>
<PopoverTrigger>
<Button
aria-label={'Pick a color'}
bgColor={color}
_hover={{ bgColor: `#${tinyColor(color).darken(10).toHex()}` }}
_active={{ bgColor: `#${tinyColor(color).darken(30).toHex()}` }}
bgColor={displayedValue}
_hover={{
bgColor: `#${tinyColor(displayedValue).darken(10).toHex()}`,
}}
_active={{
bgColor: `#${tinyColor(displayedValue).darken(30).toHex()}`,
}}
height="22px"
width="22px"
padding={0}
@@ -62,16 +68,16 @@ export const ColorPicker = ({ initialColor, onColorChange }: Props) => {
/>
</PopoverTrigger>
<PopoverContent width="170px">
<PopoverArrow bg={color} />
<PopoverArrow bg={displayedValue} />
<PopoverCloseButton color="white" />
<PopoverHeader
height="100px"
backgroundColor={color}
backgroundColor={displayedValue}
borderTopLeftRadius={5}
borderTopRightRadius={5}
color={tinyColor(color).isLight() ? 'gray.800' : 'white'}
color={tinyColor(displayedValue).isLight() ? 'gray.800' : 'white'}
>
<Center height="100%">{color}</Center>
<Center height="100%">{displayedValue}</Center>
</PopoverHeader>
<PopoverBody as={Stack}>
<SimpleGrid columns={5} spacing={2}>
@@ -96,12 +102,12 @@ export const ColorPicker = ({ initialColor, onColorChange }: Props) => {
placeholder="#2a9d8f"
aria-label="Color value"
size="sm"
value={color}
value={displayedValue}
onChange={handleColorChange}
/>
<NativeColorPicker
size="sm"
color={color}
color={displayedValue}
onColorChange={handleColorChange}
>
Advanced picker

View File

@@ -202,15 +202,6 @@ export const CodeIcon = (props: IconProps) => (
</Icon>
)
export const PencilIcon = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...featherIconsBaseProps} {...props}>
<path d="M12 19l7-7 3 3-7 7-3-3z"></path>
<path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path>
<path d="M2 2l7.586 7.586"></path>
<circle cx="11" cy="11" r="2"></circle>
</Icon>
)
export const EditIcon = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...featherIconsBaseProps} {...props}>
<path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"></path>
@@ -591,3 +582,15 @@ export const LargeRadiusIcon = (props: IconProps) => (
/>
</Icon>
)
export const DropletIcon = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...featherIconsBaseProps} {...props}>
<path d="M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z"></path>
</Icon>
)
export const TableIcon = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...featherIconsBaseProps} {...props}>
<path d="M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18"></path>
</Icon>
)

View File

@@ -24,6 +24,7 @@ import { MoreInfoTooltip } from '../MoreInfoTooltip'
type Props = {
items: string[]
value?: string
defaultValue?: string
debounceTimeout?: number
placeholder?: string
@@ -40,6 +41,7 @@ export const AutocompleteInput = ({
debounceTimeout,
placeholder,
withVariableButton = true,
value,
defaultValue,
label,
moreInfoTooltip,
@@ -178,7 +180,7 @@ export const AutocompleteInput = ({
<Input
autoComplete="off"
ref={inputRef}
value={inputValue}
value={value ?? inputValue}
onChange={(e) => changeValue(e.target.value)}
onFocus={onOpen}
onBlur={updateCarretPosition}

View File

@@ -65,7 +65,6 @@ export const CodeEditor = ({
}
const handleChange = (newValue: string) => {
if (isDefined(props.value)) return
setValue(newValue)
}

View File

@@ -11,15 +11,18 @@ import { ReactNode } from 'react'
type Props<T extends string> = {
options: (T | { value: T; label: ReactNode })[]
defaultValue: T
value?: T
defaultValue?: T
onSelect: (newValue: T) => void
}
export const RadioButtons = <T extends string>({
options,
value,
defaultValue,
onSelect,
}: Props<T>) => {
const { getRootProps, getRadioProps } = useRadioGroup({
value,
defaultValue,
onChange: onSelect,
})

View File

@@ -24,7 +24,7 @@ import { MoreInfoTooltip } from '../MoreInfoTooltip'
export type TextInputProps = {
defaultValue?: string
onChange: (value: string) => void
onChange?: (value: string) => void
debounceTimeout?: number
label?: ReactNode
helperText?: ReactNode
@@ -66,7 +66,8 @@ export const TextInput = forwardRef(function TextInput(
localValue.length ?? 0
)
const onChange = useDebouncedCallback(
_onChange,
// eslint-disable-next-line @typescript-eslint/no-empty-function
_onChange ?? (() => {}),
env('E2E_TEST') === 'true' ? 0 : debounceTimeout
)