✨ (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:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -65,7 +65,6 @@ export const CodeEditor = ({
|
||||
}
|
||||
|
||||
const handleChange = (newValue: string) => {
|
||||
if (isDefined(props.value)) return
|
||||
setValue(newValue)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user