✨ (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:
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -27,6 +27,7 @@ export const parseTestTypebot = (
|
||||
createdAt: new Date(),
|
||||
customDomain: null,
|
||||
icon: null,
|
||||
selectedThemeTemplateId: null,
|
||||
isArchived: false,
|
||||
isClosed: false,
|
||||
resultsTablePreferences: null,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user