(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

@@ -1,6 +1,6 @@
{
"name": "@typebot.io/js",
"version": "0.0.30",
"version": "0.0.31",
"description": "Javascript library to display typebots on your website",
"type": "module",
"main": "dist/index.js",

View File

@@ -159,21 +159,31 @@ const BotContent = (props: BotContentProps) => {
})
const injectCustomFont = () => {
const existingFont = document.getElementById('bot-font')
if (
existingFont
?.getAttribute('href')
?.includes(
props.initialChatReply.typebot?.theme?.general?.font ?? 'Open Sans'
)
)
return
const font = document.createElement('link')
font.href = `https://fonts.googleapis.com/css2?family=${
props.initialChatReply.typebot?.theme?.general?.font ?? 'Open Sans'
}:ital,wght@0,300;0,400;0,600;1,300;1,400;1,600&display=swap');')`
font.rel = 'stylesheet'
font.id = 'bot-font'
document.head.appendChild(font)
}
onMount(() => {
injectCustomFont()
if (!botContainer) return
resizeObserver.observe(botContainer)
})
createEffect(() => {
injectCustomFont()
if (!botContainer) return
setCssVariablesValue(props.initialChatReply.typebot.theme, botContainer)
})
@@ -187,7 +197,7 @@ const BotContent = (props: BotContentProps) => {
<div
ref={botContainer}
class={
'relative flex w-full h-full text-base overflow-hidden bg-cover flex-col items-center typebot-container ' +
'relative flex w-full h-full text-base overflow-hidden bg-cover bg-center flex-col items-center typebot-container ' +
props.class
}
>

View File

@@ -62,8 +62,8 @@ export const ChoiceForm = (props: Props) => {
</button>
{props.inputIndex === 0 && props.block.items.length === 1 && (
<span class="flex h-3 w-3 absolute top-0 right-0 -mt-1 -mr-1 ping">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full brightness-225 opacity-75" />
<span class="relative inline-flex rounded-full h-3 w-3 brightness-200" />
<span class="animate-ping absolute inline-flex h-full w-full rounded-full brightness-200 opacity-75" />
<span class="relative inline-flex rounded-full h-3 w-3 brightness-150" />
</span>
)}
</span>

View File

@@ -134,6 +134,8 @@ const setTypebotBackground = (
background: Background,
documentStyle: CSSStyleDeclaration
) => {
documentStyle.setProperty(cssVariableNames.general.bgImage, null)
documentStyle.setProperty(cssVariableNames.general.bgColor, null)
documentStyle.setProperty(
background?.type === BackgroundType.IMAGE
? cssVariableNames.general.bgImage

View File

@@ -1,6 +1,6 @@
{
"name": "@typebot.io/react",
"version": "0.0.30",
"version": "0.0.31",
"description": "React library to display typebots on your website",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@@ -27,6 +27,7 @@ export const parseTestTypebot = (
createdAt: new Date(),
customDomain: null,
icon: null,
selectedThemeTemplateId: null,
isArchived: false,
isClosed: false,
resultsTablePreferences: null,

View File

@@ -95,6 +95,7 @@ model Workspace {
customChatsLimit Int?
customStorageLimit Int?
customSeatsLimit Int?
themeTemplates ThemeTemplate[]
}
model MemberInWorkspace {
@@ -180,6 +181,7 @@ model Typebot {
variables Json
edges Json
theme Json
selectedThemeTemplateId String?
settings Json
publicId String? @unique
customDomain String? @unique
@@ -325,6 +327,18 @@ model ChatSession {
state Json
}
model ThemeTemplate {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
name String
theme Json
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
workspaceId String
@@index([workspaceId])
}
enum WorkspaceRole {
ADMIN
MEMBER

View File

@@ -0,0 +1,17 @@
-- AlterTable
ALTER TABLE "Typebot" ADD COLUMN "selectedThemeTemplateId" TEXT;
-- CreateTable
CREATE TABLE "ThemeTemplate" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"name" TEXT NOT NULL,
"theme" JSONB NOT NULL,
"workspaceId" TEXT NOT NULL,
CONSTRAINT "ThemeTemplate_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "ThemeTemplate" ADD CONSTRAINT "ThemeTemplate_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -89,6 +89,7 @@ model Workspace {
customChatsLimit Int?
customStorageLimit Int?
customSeatsLimit Int?
themeTemplates ThemeTemplate[]
}
model MemberInWorkspace {
@@ -164,6 +165,7 @@ model Typebot {
variables Json
edges Json
theme Json
selectedThemeTemplateId String?
settings Json
publicId String? @unique
customDomain String? @unique
@@ -304,6 +306,16 @@ model ChatSession {
state Json
}
model ThemeTemplate {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
name String
theme Json
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
workspaceId String
}
enum WorkspaceRole {
ADMIN
MEMBER

View File

@@ -1,3 +1,4 @@
import { ThemeTemplate as ThemeTemplatePrisma } from '@typebot.io/prisma'
import { z } from 'zod'
import { BackgroundType } from './enums'
@@ -43,6 +44,15 @@ export const themeSchema = z.object({
customCss: z.string().optional(),
})
export const themeTemplateSchema = z.object({
id: z.string(),
name: z.string(),
theme: themeSchema,
workspaceId: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
}) satisfies z.ZodType<ThemeTemplatePrisma>
export const defaultTheme: Theme = {
chat: {
hostBubbles: { backgroundColor: '#F7F8FF', color: '#303235' },
@@ -67,3 +77,4 @@ export type GeneralTheme = z.infer<typeof generalThemeSchema>
export type Background = z.infer<typeof backgroundSchema>
export type ContainerColors = z.infer<typeof containerColorsSchema>
export type InputColors = z.infer<typeof inputColorsSchema>
export type ThemeTemplate = z.infer<typeof themeTemplateSchema>

View File

@@ -46,6 +46,7 @@ export const typebotSchema = z.object({
edges: z.array(edgeSchema),
variables: z.array(variableSchema),
theme: themeSchema,
selectedThemeTemplateId: z.string().nullable(),
settings: settingsSchema,
createdAt: z.date(),
updatedAt: z.date(),