- ),
- Cta: (props) => (
-
- ),
- Table,
- }}
- />
-
-
-);
-
-function formatDate(date: string) {
- const currentDate = new Date().getTime();
- const dateWithTimezone = date.includes("T") ? date : `${date}T00:00:00`;
- const targetDate = new Date(dateWithTimezone).getTime();
- const timeDifference = Math.abs(currentDate - targetDate);
- const daysAgo = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
-
- const fullDate = new Date(dateWithTimezone).toLocaleString("en-us", {
- month: "long",
- day: "numeric",
- year: "numeric",
- });
-
- if (daysAgo < 1) {
- return "Today";
- }
- if (daysAgo < 7) {
- return `${fullDate} (${daysAgo}d ago)`;
- }
- if (daysAgo < 30) {
- const weeksAgo = Math.floor(daysAgo / 7);
- return `${fullDate} (${weeksAgo}w ago)`;
- }
- if (daysAgo < 365) {
- const monthsAgo = Math.floor(daysAgo / 30);
- return `${fullDate} (${monthsAgo}mo ago)`;
- }
- const yearsAgo = Math.floor(daysAgo / 365);
- return `${fullDate} (${yearsAgo}y ago)`;
-}
diff --git a/apps/landing-page/src/app/blog/[slug]/page.tsx b/apps/landing-page/src/app/blog/[slug]/page.tsx
deleted file mode 100644
index a3c53c2d88..0000000000
--- a/apps/landing-page/src/app/blog/[slug]/page.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { getBlogPosts } from "@/app/db/blog";
-import type { Metadata } from "next";
-import { serialize } from "next-mdx-remote/serialize";
-import { notFound } from "next/navigation";
-import { Post } from "./Post";
-import "@/assets/prose.css";
-import { env } from "@typebot.io/env";
-
-export async function generateMetadata({
- params,
-}: {
- params: { slug: string };
-}): Promise {
- const post = getBlogPosts().find(
- (post) => post.slug === params.slug && post.metadata.publishedAt,
- );
- if (!post) {
- return;
- }
-
- const {
- title,
- publishedAt: publishedTime,
- summary: description,
- image,
- } = post.metadata;
- const ogImage = image
- ? `${env.LANDING_PAGE_URL}${image}`
- : `${env.LANDING_PAGE_URL}/og?title=${title}`;
-
- return {
- title,
- description,
- openGraph: {
- title,
- description,
- type: "article",
- publishedTime,
- url: `${env.LANDING_PAGE_URL}/blog/${post.slug}`,
- images: [
- {
- url: ogImage,
- },
- ],
- },
- twitter: {
- card: "summary_large_image",
- title,
- description,
- images: [ogImage],
- },
- };
-}
-
-export default async function Blog({ params }: { params: { slug: string } }) {
- const post = getBlogPosts().find(
- (post) => post.slug === params.slug && post.metadata.publishedAt,
- );
-
- if (!post) {
- notFound();
- }
-
- const mdxSource = await serialize(post.content);
-
- return ;
-}
diff --git a/apps/landing-page/content/add-chatbot-to-wordpress.mdx b/apps/landing-page/src/app/blog/add-chatbot-to-wordpress/page.mdx
similarity index 96%
rename from apps/landing-page/content/add-chatbot-to-wordpress.mdx
rename to apps/landing-page/src/app/blog/add-chatbot-to-wordpress/page.mdx
index 89a3fc23e9..2938c7b3ba 100644
--- a/apps/landing-page/content/add-chatbot-to-wordpress.mdx
+++ b/apps/landing-page/src/app/blog/add-chatbot-to-wordpress/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'How to Add Chatbot in WordPress: Quick and Easy Way'
-description: 'Learn how to add a chatbot to your WordPress site using Typebot.'
-publishedAt: '2024-06-20'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "How to Add Chatbot in WordPress: Quick and Easy Way",
+ description:
+ "Learn how to add a chatbot to your WordPress site using Typebot",
+ postedAt: new Date("2024-06-20"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Imagine having a virtual assistant that can engage with your website visitors 24/7. It could answer their questions, guide them through your products or services, and even capture leads. That's the power of chatbots. Adding one to your WordPress site is now simpler than ever.
diff --git a/apps/landing-page/content/ai-open-source-tools.mdx b/apps/landing-page/src/app/blog/ai-open-source-tools/page.mdx
similarity index 96%
rename from apps/landing-page/content/ai-open-source-tools.mdx
rename to apps/landing-page/src/app/blog/ai-open-source-tools/page.mdx
index cbe05d5e71..1ed6829500 100644
--- a/apps/landing-page/content/ai-open-source-tools.mdx
+++ b/apps/landing-page/src/app/blog/ai-open-source-tools/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Top 10 AI Open Source Tools for Your Business'
-summary: 'Discover top AI open source tools to boost your business. Learn how these innovative solutions can enhance operations, save costs, and drive growth. Explore now!'
-publishedAt: '2024-09-05'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Top 10 AI Open Source Tools for Your Business",
+ description:
+ "Disover top AI open source tools to boost your business. Learn how these innovative solutions can enhance operations, save costs, and drive growth. Explore now!",
+ postedAt: new Date("2024-09-05"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
**[Open-source](https://typebot.io/blog/open-source-chatbots) AI tools** offer powerful solutions without breaking the bank or sacrificing data control. These tools are changing how businesses innovate. From collaborative AI agents to local language models, this article explores the top 10 AI open source tools that can enhance your operations. Learn how these technologies are making new opportunities available for businesses of all sizes.
diff --git a/apps/landing-page/content/benefits-ai-chatbot.mdx b/apps/landing-page/src/app/blog/benefits-ai-chatbot/page.mdx
similarity index 94%
rename from apps/landing-page/content/benefits-ai-chatbot.mdx
rename to apps/landing-page/src/app/blog/benefits-ai-chatbot/page.mdx
index 24995413db..30ec24bf14 100644
--- a/apps/landing-page/content/benefits-ai-chatbot.mdx
+++ b/apps/landing-page/src/app/blog/benefits-ai-chatbot/page.mdx
@@ -1,8 +1,16 @@
----
-title: '16 Benefits of AI Chatbots that will Convince Skeptics'
-summary: 'Discover 16 game-changing benefits of AI chatbots that boost customer service, drive sales, and cut costs. Learn how to implement this powerful tool for your business success.'
-publishedAt: '2024-07-31'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "16 Benefits of AI Chatbots that will Convince Skeptics",
+ description:
+ "Discover 16 game-changing benefits of AI chatbots that boost customer service, drive sales, and cut costs. Learn how to implement this powerful tool for your business success.",
+ postedAt: new Date("2024-07-31"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
AI chatbots offer **round-the-clock customer service**, speak multiple languages, and learn from every interaction. These digital assistants don't just cut response times—they also help boost sales.
diff --git a/apps/landing-page/content/best-chatbot-for-wordpress.mdx b/apps/landing-page/src/app/blog/best-chatbot-for-wordpress/page.mdx
similarity index 98%
rename from apps/landing-page/content/best-chatbot-for-wordpress.mdx
rename to apps/landing-page/src/app/blog/best-chatbot-for-wordpress/page.mdx
index 1d3b80c5b1..1020d8fc2e 100644
--- a/apps/landing-page/content/best-chatbot-for-wordpress.mdx
+++ b/apps/landing-page/src/app/blog/best-chatbot-for-wordpress/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Top 10 Best Chatbot for Your Wordpress Website in 2024'
-summary: 'Discover the top 10 WordPress chatbot plugins to boost customer service, generate leads, and increase engagement. Find the best fit for your website'
-publishedAt: '2024-05-02'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Top 10 Best Chatbot for Your Wordpress Website in 2024",
+ description:
+ "Discover the top 10 WordPress chatbot plugins to boost customer service, generate leads, and increase engagement. Find the best fit for your website",
+ postedAt: new Date("2024-05-02"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
**Seamless communication with customers is crucial for business success**. As more interactions move online, chatbots have emerged as a game-changer, enabling 24/7 support and personalized engagement.
diff --git a/apps/landing-page/content/best-crm-for-shopify.mdx b/apps/landing-page/src/app/blog/best-crm-for-shopify/page.mdx
similarity index 96%
rename from apps/landing-page/content/best-crm-for-shopify.mdx
rename to apps/landing-page/src/app/blog/best-crm-for-shopify/page.mdx
index b9089f8483..001352b4d7 100644
--- a/apps/landing-page/content/best-crm-for-shopify.mdx
+++ b/apps/landing-page/src/app/blog/best-crm-for-shopify/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Top 5 Best CRM for Shopify'
-description: 'Discover the best CRM solutions for Shopify to boost customer engagement. Streamline interactions, and automate tasks with our top picks and expert tips.'
-publishedAt: '2024-06-14'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Top 10 Best Chatbot for Your Wordpress Website in 2024",
+ description:
+ "Discover the best CRM solutions to boost customer service, generate leads, and increase engagement. Find the best fit for your website",
+ postedAt: new Date("2024-06-14"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
A powerful CRM tool can greatly improve **customer interactions** and enhance **sales and marketing efforts**. The right CRM solution for your Shopify store can help you deliver fantastic customer experiences. This, in turn, helps you stand out and grow in the competitive eCommerce world.
diff --git a/apps/landing-page/content/best-marketing-chatgpt-prompts.mdx b/apps/landing-page/src/app/blog/best-marketing-chatgpt-prompts/page.mdx
similarity index 97%
rename from apps/landing-page/content/best-marketing-chatgpt-prompts.mdx
rename to apps/landing-page/src/app/blog/best-marketing-chatgpt-prompts/page.mdx
index 6564a8c5f8..0b90ae382d 100644
--- a/apps/landing-page/content/best-marketing-chatgpt-prompts.mdx
+++ b/apps/landing-page/src/app/blog/best-marketing-chatgpt-prompts/page.mdx
@@ -1,8 +1,16 @@
----
-title: '10 Best Marketing ChatGPT Prompts for Content Creation and More'
-summary: 'Unlock the power of AI with these 10 best ChatGPT prompts for marketing - from content creation to email campaigns, brainstorming, social media, and more. '
-publishedAt: '2024-05-31'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "10 Best Marketing ChatGPT Prompts for Content Creation and More",
+ description:
+ "Unlock the power of AI with these 10 best ChatGPT prompts for marketing - from content creation to email campaigns, brainstorming, social media, and more.",
+ postedAt: new Date("2024-05-31"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Imagine having a marketing assistant who never sleeps, understands your every need, and delivers outstanding content on demand. No, it’s not a dream, it’s the power of ChatGPT.
diff --git a/apps/landing-page/content/best-whatsapp-chatbot.mdx b/apps/landing-page/src/app/blog/best-whatsapp-chatbot/page.mdx
similarity index 96%
rename from apps/landing-page/content/best-whatsapp-chatbot.mdx
rename to apps/landing-page/src/app/blog/best-whatsapp-chatbot/page.mdx
index 420a83cdfa..1cefedbe92 100644
--- a/apps/landing-page/content/best-whatsapp-chatbot.mdx
+++ b/apps/landing-page/src/app/blog/best-whatsapp-chatbot/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Top 5 Best WhatsApp Chatbot Tools Compared'
-summary: 'Discover the top 5 WhatsApp chatbot platforms for businesses in 2024. Compare features, pricing, and use cases to choose the best solution to your business'
-publishedAt: '2024-04-25'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Top 5 Best WhatsApp Chatbot Tools Compared",
+ description:
+ "Discover the top 5 WhatsApp chatbot platforms for businesses in 2024. Compare features, pricing, and use cases to choose the best solution to your business",
+ postedAt: new Date("2024-04-25"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
**Did you know that over 2 billion people use WhatsApp worldwide?** With such a massive global user base, it's no wonder businesses are scrambling to leverage WhatsApp as a channel for customer communication and engagement. But with so many chatbot solutions on the market, how do you choose the **best WhatsApp chatbot** for your needs? In this comprehensive guide, we'll compare the top 5 WhatsApp chatbot tools and dive deep into their features, strengths, weaknesses, and ideal use cases.
diff --git a/apps/landing-page/content/chatbot-best-practices.mdx b/apps/landing-page/src/app/blog/chatbot-best-practices/page.mdx
similarity index 97%
rename from apps/landing-page/content/chatbot-best-practices.mdx
rename to apps/landing-page/src/app/blog/chatbot-best-practices/page.mdx
index 3f8dde4236..f43b07b5e4 100644
--- a/apps/landing-page/content/chatbot-best-practices.mdx
+++ b/apps/landing-page/src/app/blog/chatbot-best-practices/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Chatbot Best Practices for 2024'
-summary: 'Discover cutting-edge chatbot best practices for 2024. Boost engagement with non-invasive AI, personalization, and seamless integrations. '
-publishedAt: '2024-09-23'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Chatbot Best Practices for 2024",
+ description:
+ "Discover cutting-edge chatbot best practices for 2024. Boost engagement with non-invasive AI, personalization, and seamless integrations. ",
+ postedAt: new Date("2024-09-23"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
In 2024, chatbot design is changing significantly. Chatbots are no longer intrusive, one-size-fits-all bots. They have evolved into sophisticated AI agents that perform tasks seamlessly across multiple channels.
diff --git a/apps/landing-page/content/chatbot-com-alternatives.mdx b/apps/landing-page/src/app/blog/chatbot-com-alternatives/page.mdx
similarity index 96%
rename from apps/landing-page/content/chatbot-com-alternatives.mdx
rename to apps/landing-page/src/app/blog/chatbot-com-alternatives/page.mdx
index 3acd12479f..6b34369f97 100644
--- a/apps/landing-page/content/chatbot-com-alternatives.mdx
+++ b/apps/landing-page/src/app/blog/chatbot-com-alternatives/page.mdx
@@ -1,8 +1,16 @@
----
-title: "Chatbot.com Alternatives: Top 5 Chatbot Solutions for 2024"
-summary: "Discover top Chatbot.com alternatives for 2024. Compare features, pricing, and user reviews to find the perfect chatbot solution."
-publishedAt: "2024-07-24"
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Chatbot.com Alternatives: Top 5 Chatbot Solutions for 2024",
+ description:
+ "Discover top Chatbot.com alternatives for 2024. Compare features, pricing, and user reviews to find the perfect chatbot solution.",
+ postedAt: new Date("2024-07-24"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Finding the right chatbot solution can make a huge difference for your business. While Chatbot.com has its strengths, you might seek better pricing, tailored features, or enhanced AI capabilities.
diff --git a/apps/landing-page/content/chatbot-script-examples.mdx b/apps/landing-page/src/app/blog/chatbot-script-examples/page.mdx
similarity index 97%
rename from apps/landing-page/content/chatbot-script-examples.mdx
rename to apps/landing-page/src/app/blog/chatbot-script-examples/page.mdx
index 021ba0c69d..6d99bdaf65 100644
--- a/apps/landing-page/content/chatbot-script-examples.mdx
+++ b/apps/landing-page/src/app/blog/chatbot-script-examples/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Creating Powerful Chatbot Script: examples, tips, prompts'
-summary: 'Discover powerful chatbot script examples. Learn tips and best practices for creating conversations that drive results.'
-publishedAt: '2024-08-14'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Creating Powerful Chatbot Script: examples, tips, prompts",
+ description:
+ "Discover powerful chatbot script examples. Learn tips and best practices for creating conversations that drive results.",
+ postedAt: new Date("2024-08-14"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Some chatbots feel like talking to a wall, while others seem to read your mind. The secret lies in the script.
diff --git a/apps/landing-page/content/chatfuel-alternatives.mdx b/apps/landing-page/src/app/blog/chatfuel-alternatives/page.mdx
similarity index 95%
rename from apps/landing-page/content/chatfuel-alternatives.mdx
rename to apps/landing-page/src/app/blog/chatfuel-alternatives/page.mdx
index 96907e5d8e..9594f26a6c 100644
--- a/apps/landing-page/content/chatfuel-alternatives.mdx
+++ b/apps/landing-page/src/app/blog/chatfuel-alternatives/page.mdx
@@ -1,8 +1,16 @@
----
-title: "Chatfuel Alternatives: Which Platform Fits Your Business Best?"
-summary: "Discover the best Chatfuel alternatives for building engaging chatbots. Our comprehensive guide explores top platforms, features, and actionable tips."
-publishedAt: "2024-06-03"
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Chatfuel Alternatives: Which Platform Fits Your Business Best?",
+ description:
+ "Discover the best Chatfuel alternatives for building engaging chatbots. Our comprehensive guide explores top platforms, features, and actionable tips.",
+ postedAt: new Date("2024-06-03"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Are you tired of Chatfuel's limitations and seeking a more powerful chatbot solution?
diff --git a/apps/landing-page/content/create-whatsapp-chatbot.mdx b/apps/landing-page/src/app/blog/create-whatsapp-chatbot/page.mdx
similarity index 97%
rename from apps/landing-page/content/create-whatsapp-chatbot.mdx
rename to apps/landing-page/src/app/blog/create-whatsapp-chatbot/page.mdx
index cc2d977c2d..c8b196dcec 100644
--- a/apps/landing-page/content/create-whatsapp-chatbot.mdx
+++ b/apps/landing-page/src/app/blog/create-whatsapp-chatbot/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Create WhatsApp Chatbot: A Step-by-Step Guide'
-summary: 'Discover how to create an engaging WhatsApp chatbot with Typebot's intuitive no-code platform.'
-publishedAt: '2024-05-09'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Create WhatsApp Chatbot: A Step-by-Step Guide",
+ description:
+ "Discover how to create an engaging WhatsApp chatbot with Typebot's intuitive no-code platform.",
+ postedAt: new Date("2024-05-09"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Imagine being able to reach your customers or audience instantly. You can do this through the messaging app they use every day - WhatsApp. Create a chatbot for Whatsapp allows you to provide a seamless and convenient way to interact with your audience.
diff --git a/apps/landing-page/content/customer-success-manager-job-description.mdx b/apps/landing-page/src/app/blog/customer-success-manager-job-description/page.mdx
similarity index 97%
rename from apps/landing-page/content/customer-success-manager-job-description.mdx
rename to apps/landing-page/src/app/blog/customer-success-manager-job-description/page.mdx
index 242ac00bb9..611571b78e 100644
--- a/apps/landing-page/content/customer-success-manager-job-description.mdx
+++ b/apps/landing-page/src/app/blog/customer-success-manager-job-description/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Customer Success Manager Job Description: 3 Templates for 2024'
-summary: 'Craft a great customer success manager job description. We will explore examples for different career stages and highlight the traits that make a CSM stand out'
-publishedAt: '2024-06-05'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Customer Success Manager Job Description: 3 Templates for 2024",
+ description:
+ "Craft a great customer success manager job description. We will explore examples for different career stages and highlight the traits that make a CSM stand out",
+ postedAt: new Date("2024-06-05"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
A Customer Success Manager (CSM) knows your customers well and ensures they keep coming back. As businesses focus more on customer retention and satisfaction, the role of a CSM becomes essential.
diff --git a/apps/landing-page/content/ecommerce-chatbot.mdx b/apps/landing-page/src/app/blog/ecommerce-chatbot/page.mdx
similarity index 97%
rename from apps/landing-page/content/ecommerce-chatbot.mdx
rename to apps/landing-page/src/app/blog/ecommerce-chatbot/page.mdx
index 6badbe2c6b..7cadf54897 100644
--- a/apps/landing-page/content/ecommerce-chatbot.mdx
+++ b/apps/landing-page/src/app/blog/ecommerce-chatbot/page.mdx
@@ -1,8 +1,16 @@
----
-title: "Using Chatbots in Ecommerce: All you need to know"
-publishedAt: "2024-07-19"
-summary: "Checkout the best chatbot solutions. Discover how AI-powered virtual assistants revolutionize customer experiences, drive sales, and streamline operations."
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Using Chatbots in Ecommerce: All you need to know",
+ description:
+ "Checkout the best chatbot solutions. Discover how AI-powered virtual assistants revolutionize customer experiences, drive sales, and streamline operations.",
+ postedAt: new Date("2024-07-19"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Providing exceptional customer service is paramount for **ecommerce businesses** to thrive. Online shoppers demand instant gratification and personalized experiences. Chatbots have emerged as a game-changing solution.
diff --git a/apps/landing-page/content/example.mdx b/apps/landing-page/src/app/blog/example/page.mdx
similarity index 74%
rename from apps/landing-page/content/example.mdx
rename to apps/landing-page/src/app/blog/example/page.mdx
index 12570b0af6..9da34b7c63 100644
--- a/apps/landing-page/content/example.mdx
+++ b/apps/landing-page/src/app/blog/example/page.mdx
@@ -1,7 +1,14 @@
----
-title: 'Blog post example'
-summary: 'A short summary of the blog post.'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Blog post example",
+ description: "A short summary of the blog post.",
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
diff --git a/apps/landing-page/content/landbot-alternative.mdx b/apps/landing-page/src/app/blog/landbot-alternative/page.mdx
similarity index 93%
rename from apps/landing-page/content/landbot-alternative.mdx
rename to apps/landing-page/src/app/blog/landbot-alternative/page.mdx
index 83a75c3584..fb4ca40997 100644
--- a/apps/landing-page/content/landbot-alternative.mdx
+++ b/apps/landing-page/src/app/blog/landbot-alternative/page.mdx
@@ -1,8 +1,16 @@
----
-title: "Top 5 Alternatives to Landbot"
-summary: "Discover the top 5 Landbot alternatives for creating engaging chatbots without coding. Compare features, pricing, and integrations to find the best fit."
-publishedAt: "2024-04-19"
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Top 5 Alternatives to Landbot",
+ description:
+ "Discover the top 5 Landbot alternatives for creating engaging chatbots without coding. Compare features, pricing, and integrations to find the best fit.",
+ postedAt: new Date("2024-04-19"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
**Chatbots have become an essential tool for modern businesses looking to enhance customer engagement and streamline support.** With the right chatbot platform, you can create interactive experiences that guide users, answer questions, and even close sales.
diff --git a/apps/landing-page/content/lead-generation-chatbot.mdx b/apps/landing-page/src/app/blog/lead-generation-chatbot/page.mdx
similarity index 96%
rename from apps/landing-page/content/lead-generation-chatbot.mdx
rename to apps/landing-page/src/app/blog/lead-generation-chatbot/page.mdx
index 21deec34b8..f0003144bd 100644
--- a/apps/landing-page/content/lead-generation-chatbot.mdx
+++ b/apps/landing-page/src/app/blog/lead-generation-chatbot/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Lead Generation Chatbot: The Ultimate Guide to Boosting Your Sales'
-summary: 'Discover how lead generation chatbots can revolutionize your business. Boost engagement, conversions, and sales with AI-powered chatbots. Learn best practices and see examples from top companies.'
-publishedAt: '2024-04-22'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Lead Generation Chatbot: The Ultimate Guide to Boosting Your Sales",
+ description:
+ "Discover how lead generation chatbots can revolutionize your business. Boost engagement, conversions, and sales with AI-powered chatbots. Learn best practices and see examples from top companies.",
+ postedAt: new Date("2024-04-22"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
**Lead generation chatbots** have become an essential tool for businesses looking to boost their sales efforts. Imagine having a highly efficient team member who is available around the clock. This team member is ready to engage with potential customers and guide them through the sales funnel.
diff --git a/apps/landing-page/content/manychat-alternatives.mdx b/apps/landing-page/src/app/blog/manychat-alternatives/page.mdx
similarity index 95%
rename from apps/landing-page/content/manychat-alternatives.mdx
rename to apps/landing-page/src/app/blog/manychat-alternatives/page.mdx
index 5c6dfbc6de..3e6a0a4ffc 100644
--- a/apps/landing-page/content/manychat-alternatives.mdx
+++ b/apps/landing-page/src/app/blog/manychat-alternatives/page.mdx
@@ -1,8 +1,16 @@
----
-title: "5 Top ManyChat Alternatives to Supercharge Your Chatbots"
-summary: "Discover top ManyChat alternatives to elevate your chatbot strategy. Explore powerful platforms with AI, multi-channel support, and customizable workflows for better conversational marketing."
-publishedAt: "2024-10-03"
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "5 Top ManyChat Alternatives to Supercharge Your Chatbots",
+ description:
+ "Discover top ManyChat alternatives to elevate your chatbot strategy. Explore powerful platforms with AI, multi-channel support, and customizable workflows for better conversational marketing.",
+ postedAt: new Date("2024-10-03"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Are you feeling constrained by ManyChat's limitations? You're not alone. Many businesses seek more flexible and powerful chatbot solutions.
diff --git a/apps/landing-page/content/open-source-chatbots.mdx b/apps/landing-page/src/app/blog/open-source-chatbots/page.mdx
similarity index 96%
rename from apps/landing-page/content/open-source-chatbots.mdx
rename to apps/landing-page/src/app/blog/open-source-chatbots/page.mdx
index 89acd61c67..c548df6f62 100644
--- a/apps/landing-page/content/open-source-chatbots.mdx
+++ b/apps/landing-page/src/app/blog/open-source-chatbots/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Open Source Chatbots: Features, Benefits, and Best Platforms'
-summary: 'Discover the power of open source chatbots! Learn about top platforms, key features, and how to choose the best one for your business.'
-publishedAt: '2024-08-07'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Open Source Chatbots: Features, Benefits, and Best Platforms",
+ description:
+ "Discover the power of open source chatbots! Learn about top platforms, key features, and how to choose the best one for your business.",
+ postedAt: new Date("2024-08-07"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
**Open-source chatbots** empower businesses to create customizable and cost-effective automated solutions. These tools transform customer engagement strategies. In this article, we examine their features, benefits, and top platforms.
diff --git a/apps/landing-page/src/app/blog/page.tsx b/apps/landing-page/src/app/blog/page.tsx
index bdfe60b62c..34a3d0a1d5 100644
--- a/apps/landing-page/src/app/blog/page.tsx
+++ b/apps/landing-page/src/app/blog/page.tsx
@@ -1,5 +1,28 @@
-import { getBlogPosts } from "@/app/db/blog";
-import { Posts } from "./Posts";
+import { Posts } from "@/features/blog/components/Posts";
+import type { BlogPost, BlogPostModel } from "@/features/blog/types";
+import glob from "fast-glob";
+
+const importPost = async (postFilename: string): Promise => {
+ const slug = postFilename
+ .replace(/(\/page)?\.mdx$/, "")
+ .split("/")
+ .pop();
+ if (!slug)
+ throw new Error(`Could not parse slug from filename: ${postFilename}`);
+ const postModule = await import(`${postFilename}`);
+ const postModel = postModule.post as BlogPostModel;
+ return {
+ slug,
+ ...postModel,
+ };
+};
+
+const findAllPosts = async (): Promise => {
+ const postFilenames = await glob("**/page.mdx", {
+ cwd: ".",
+ });
+ return await Promise.all(postFilenames.map(importPost));
+};
export const metadata = {
title: "Typebot Blog",
@@ -7,8 +30,8 @@ export const metadata = {
"The official Typebot blog where we share our thoughts and tips on everything related to chatbots, conversational marketing, customer support and more.",
};
-export default function Home() {
- const allBlogs = getBlogPosts();
+export default async function Home() {
+ const posts = await findAllPosts();
- return ;
+ return ;
}
diff --git a/apps/landing-page/content/react-chatbot.mdx b/apps/landing-page/src/app/blog/react-chatbot/page.mdx
similarity index 74%
rename from apps/landing-page/content/react-chatbot.mdx
rename to apps/landing-page/src/app/blog/react-chatbot/page.mdx
index e55602b475..11178f7264 100644
--- a/apps/landing-page/content/react-chatbot.mdx
+++ b/apps/landing-page/src/app/blog/react-chatbot/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'How to Build a React Chatbot: Three Methods Explained'
-description: 'Learn how to build a React chatbot using three methods: no-code, API integration, and full-stack development.'
-publishedAt: '2024-07-11'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "How to Build a React Chatbot: Three Methods Explained",
+ description:
+ "Learn how to build a React chatbot using three methods: no-code, API integration, and full-stack development.",
+ postedAt: new Date("2024-07-11"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
To enhance user engagement in your React application, adding a chatbot can be a game changer. You don't need to get overwhelmed by complex code. React chatbots offer interactive and responsive interfaces.
@@ -47,32 +55,32 @@ Typebot is an open-source platform that makes it easy to create chatbots for Rea
### Real-World Use Cases of React Chatbots
@@ -118,13 +126,13 @@ npm install @typebot.io/js @typebot.io/react
5. Create a new component in your React app:
```jsx
-import { Bubble } from '@typebot.io/react'
+import { Bubble } from "@typebot.io/react";
const ChatbotComponent = () => {
- return
-}
+ return ;
+};
-export default ChatbotComponent
+export default ChatbotComponent;
```
### Adding Typebot Chatbot to Existing React Applications
@@ -132,7 +140,7 @@ export default ChatbotComponent
1. Import the **ChatbotComponent** where needed:
```jsx
-import ChatbotComponent from './ChatbotComponent'
+import ChatbotComponent from "./ChatbotComponent";
function App() {
return (
@@ -140,7 +148,7 @@ function App() {
- )
-}
+ );
+};
-export default ChatComponent
+export default ChatComponent;
```
### Deploying and Testing
@@ -588,12 +596,12 @@ By following these steps, you can create a full-stack **React chatbot** with a c
Update the axios call in `ChatComponent.tsx` to use an environment variable:
```typescript
-const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001'
+const API_URL = import.meta.env.VITE_API_URL || "http://localhost:3001";
// In handleSendMessage:
const response = await axios.post(`${API_URL}/api/chat`, {
message: inputMessage,
-})
+});
```
### Error Handling and Debugging
@@ -605,11 +613,11 @@ Implement error handling in both frontend and backend:
try {
// API call
} catch (error) {
- console.error('Error sending message:', error)
+ console.error("Error sending message:", error);
setMessages((prevMessages) => [
...prevMessages,
- { text: 'An error occurred. Please try again.', isUser: false },
- ])
+ { text: "An error occurred. Please try again.", isUser: false },
+ ]);
}
// Backend (server.ts)
@@ -620,10 +628,10 @@ app.use(
res: express.Response,
next: express.NextFunction
) => {
- console.error(err.stack)
- res.status(500).send('Something broke!')
+ console.error(err.stack);
+ res.status(500).send("Something broke!");
}
-)
+);
```
### Best Practices for State Management
@@ -663,24 +671,24 @@ Implement branching conversations based on user inputs:
```typescript
const generateResponse = (message: string, context: any): string => {
- if (context.stage === 'greeting') {
- if (message.toLowerCase().includes('help')) {
- context.stage = 'help'
- return 'What kind of help do you need? 1. Technical Support 2. Account Issues 3. Billing'
+ if (context.stage === "greeting") {
+ if (message.toLowerCase().includes("help")) {
+ context.stage = "help";
+ return "What kind of help do you need? 1. Technical Support 2. Account Issues 3. Billing";
} else {
- return 'Hello! How can I assist you today?'
+ return "Hello! How can I assist you today?";
}
- } else if (context.stage === 'help') {
- if (message.includes('1')) {
- return 'For technical support, please describe your issue.'
- } else if (message.includes('2')) {
- return 'For account issues, please provide your account number.'
- } else if (message.includes('3')) {
- return "For billing inquiries, I'll transfer you to our billing department."
+ } else if (context.stage === "help") {
+ if (message.includes("1")) {
+ return "For technical support, please describe your issue.";
+ } else if (message.includes("2")) {
+ return "For account issues, please provide your account number.";
+ } else if (message.includes("3")) {
+ return "For billing inquiries, I'll transfer you to our billing department.";
}
}
- return "I'm not sure how to respond. Can you please clarify?"
-}
+ return "I'm not sure how to respond. Can you please clarify?";
+};
```
### Integrations with Third-Party Services
@@ -688,13 +696,13 @@ const generateResponse = (message: string, context: any): string => {
#### OpenAI Integration
```typescript
-import { Configuration, OpenAIApi } from 'openai'
+import { Configuration, OpenAIApi } from "openai";
// Initialize the OpenAI configuration
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
-})
-const openai = new OpenAIApi(configuration)
+});
+const openai = new OpenAIApi(configuration);
const generateResponse = async (
message: string,
@@ -702,52 +710,52 @@ const generateResponse = async (
): Promise => {
try {
const completion = await openai.createChatCompletion({
- model: 'gpt-3.5-turbo', // You can change this to a different model if needed
+ model: "gpt-3.5-turbo", // You can change this to a different model if needed
messages: [
{
- role: 'system',
- content: 'You are a helpful customer service assistant.',
+ role: "system",
+ content: "You are a helpful customer service assistant.",
},
{
- role: 'user',
+ role: "user",
content: `Current stage: ${context.stage}. User message: ${message}`,
},
],
max_tokens: 150, // Adjust as needed
temperature: 0.7, // Adjust for more or less randomness in responses
- })
+ });
return (
completion.data.choices[0].message?.content ||
"I'm sorry, I couldn't generate a response."
- )
+ );
} catch (error) {
- console.error('Error calling OpenAI API:', error)
- return "I'm sorry, there was an error processing your request."
+ console.error("Error calling OpenAI API:", error);
+ return "I'm sorry, there was an error processing your request.";
}
-}
+};
```
#### Google Sheets Integration
```typescript
-import { google } from 'googleapis'
+import { google } from "googleapis";
const sheets = google.sheets({
- version: 'v4',
+ version: "v4",
auth: process.env.GOOGLE_API_KEY,
-})
+});
const logToSheet = async (message: string, response: string) => {
await sheets.spreadsheets.values.append({
- spreadsheetId: 'YOUR_SHEET_ID',
- range: 'Sheet1!A:C',
- valueInputOption: 'USER_ENTERED',
+ spreadsheetId: "YOUR_SHEET_ID",
+ range: "Sheet1!A:C",
+ valueInputOption: "USER_ENTERED",
requestBody: {
values: [[new Date().toISOString(), message, response]],
},
- })
-}
+ });
+};
```
### Theming and Custom UI Design
@@ -761,16 +769,16 @@ module.exports = {
themes: [
{
mytheme: {
- primary: '#4B5563',
- secondary: '#60A5FA',
- accent: '#37CDBE',
- neutral: '#3D4451',
- 'base-100': '#FFFFFF',
+ primary: "#4B5563",
+ secondary: "#60A5FA",
+ accent: "#37CDBE",
+ neutral: "#3D4451",
+ "base-100": "#FFFFFF",
},
},
],
},
-}
+};
```
### Performance Optimization
@@ -780,9 +788,9 @@ module.exports = {
3. Optimize API calls with debouncing or throttling.
```typescript
-import { useDebounce } from 'use-debounce'
+import { useDebounce } from "use-debounce";
-const [value] = useDebounce(text, 1000)
+const [value] = useDebounce(text, 1000);
```
Building a **React chatbot** offers diverse approaches, from no-code solutions to full-stack implementations. This article explored three methods: using Typebot for rapid deployment, integrating Typebot's API for customization, and building a complete solution from scratch.
diff --git a/apps/landing-page/content/train-chatbot-on-your-own-data.mdx b/apps/landing-page/src/app/blog/train-chatbot-on-your-own-data/page.mdx
similarity index 96%
rename from apps/landing-page/content/train-chatbot-on-your-own-data.mdx
rename to apps/landing-page/src/app/blog/train-chatbot-on-your-own-data/page.mdx
index b56107c53f..ab2035ef84 100644
--- a/apps/landing-page/content/train-chatbot-on-your-own-data.mdx
+++ b/apps/landing-page/src/app/blog/train-chatbot-on-your-own-data/page.mdx
@@ -1,8 +1,16 @@
----
-title: How to Train Chatbot on Your Own Data with Typebot and ChatGPT
-description: Maximize your chatbot's potential with Typebot and OpenAI's ChatGPT. This guide offers a step-by-step tutorial on creating a personalized assistant.
-publishedAt: 2024-05-16
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "How to Train Chatbot on Your Own Data with Typebot and ChatGPT",
+ description:
+ "Maximize your chatbot's potential with Typebot and OpenAI's ChatGPT. This guide offers a step-by-step tutorial on creating a personalized assistant.",
+ postedAt: new Date("2024-05-16"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Imagine having a chatbot that understands your unique needs and can answer all your Typebot-related queries flawlessly. Sounds like magic, right? With the power of Typebot and OpenAI's ChatGPT, you can create a custom assistant trained on your own data. This guide will walk you through the exact steps to make this happen, so you can focus on what really matters—engaging with your users. Ready to transform your chatbot experience?
diff --git a/apps/landing-page/content/typebot-is-now-fair-source.mdx b/apps/landing-page/src/app/blog/typebot-is-now-fair-source/page.mdx
similarity index 91%
rename from apps/landing-page/content/typebot-is-now-fair-source.mdx
rename to apps/landing-page/src/app/blog/typebot-is-now-fair-source/page.mdx
index 331c4a0ac2..edb0ec719f 100644
--- a/apps/landing-page/content/typebot-is-now-fair-source.mdx
+++ b/apps/landing-page/src/app/blog/typebot-is-now-fair-source/page.mdx
@@ -1,8 +1,16 @@
----
-title: Typebot is now Fair Source
-description: Typebot is migrating from AGPLv3 to FSL, a new license that gives maximum while ensuring fairness for the project owner.
-publishedAt: 2024-09-30
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Typebot is now Fair Source",
+ description:
+ "Typebot is migrating from AGPLv3 to FSL, a new license that gives maximum while ensuring fairness for the project owner.",
+ postedAt: new Date("2024-09-30"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
## AGPLv3
diff --git a/apps/landing-page/content/upsell-using-ai-chatbot.mdx b/apps/landing-page/src/app/blog/upsell-using-ai-chatbot/page.mdx
similarity index 96%
rename from apps/landing-page/content/upsell-using-ai-chatbot.mdx
rename to apps/landing-page/src/app/blog/upsell-using-ai-chatbot/page.mdx
index f721e5300f..ba0bb844db 100644
--- a/apps/landing-page/content/upsell-using-ai-chatbot.mdx
+++ b/apps/landing-page/src/app/blog/upsell-using-ai-chatbot/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Upsell Using AI Chatbot: Boost Your Revenue on Shopify'
-description: 'Boost your Shopify revenue with AI chatbot upselling. Learn to create, integrate, and optimize an AI assistant that turns browsers into buyers.'
-publishedAt: '2024-06-26'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Upsell Using AI Chatbot: Boost Your Revenue on Shopify",
+ description:
+ "Boost your Shopify revenue with AI chatbot upselling. Learn to create, integrate, and optimize an AI assistant that turns browsers into buyers.",
+ postedAt: new Date("2024-06-26"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Imagine turning every product page on your Shopify store into a savvy salesperson, one that never sleeps and always knows the perfect upsell. Sounds like a retailer's dream, right? Well, buckle up, because we're about to turn that dream into reality using AI chatbots.
@@ -188,7 +196,7 @@ In Typebot, create a new variable called "Current product". Select 'Custom' in V
and activate 'Execute on client'. Put this code in the field:
```jsx
-document.querySelector('h1').innerText
+document.querySelector("h1").innerText;
```
This little bit of code tells Typebot, "Hey, the customer is looking at this product right now!"
@@ -417,12 +425,12 @@ Numbers don't lie, folks. Let's get down to the nitty-gritty of performance anal
Here's a quick snapshot of what your metrics dashboard might look like:
diff --git a/apps/landing-page/content/webflow-chatbot.mdx b/apps/landing-page/src/app/blog/webflow-chatbot/page.mdx
similarity index 95%
rename from apps/landing-page/content/webflow-chatbot.mdx
rename to apps/landing-page/src/app/blog/webflow-chatbot/page.mdx
index 9a3300eaae..09e31e8dde 100644
--- a/apps/landing-page/content/webflow-chatbot.mdx
+++ b/apps/landing-page/src/app/blog/webflow-chatbot/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Add Chatbot to Webflow: Easy Integration Guide Without Code'
-summary: 'Learn how to add a chatbot to Webflow easily. Boost engagement with AI-powered interactions, step-by-step integration guide, and customizable templates. Transform your site today!'
-publishedAt: '2024-09-25'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Add Chatbot to Webflow: Easy Integration Guide Without Code",
+ description:
+ "Learn how to add a chatbot to Webflow easily. Boost engagement with AI-powered interactions, step-by-step integration guide, and customizable templates. Transform your site today!",
+ postedAt: new Date("2024-09-25"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Transform your static Webflow site into an interactive, AI-powered customer service hub. By adding a chatbot to Webflow, you revolutionize how you engage with visitors.
diff --git a/apps/landing-page/content/webflow-popup-contact-form.mdx b/apps/landing-page/src/app/blog/webflow-popup-contact-form/page.mdx
similarity index 94%
rename from apps/landing-page/content/webflow-popup-contact-form.mdx
rename to apps/landing-page/src/app/blog/webflow-popup-contact-form/page.mdx
index 5740531150..1865f5b117 100644
--- a/apps/landing-page/content/webflow-popup-contact-form.mdx
+++ b/apps/landing-page/src/app/blog/webflow-popup-contact-form/page.mdx
@@ -1,8 +1,16 @@
----
-title: 'Create a Stunning Webflow Popup Contact Form in Minutes'
-summary: 'Learn how to create an eye-catching Webflow popup contact form in minutes. Boost engagement, capture leads, and enhance your website's design with this step-by-step guide.'
-publishedAt: '2024-09-11'
----
+import Post from "@/features/blog/components/Post";
+import { generateMetadata } from "@/features/blog/helpers";
+
+export const post = {
+ title: "Create a Stunning Webflow Popup Contact Form in Minutes",
+ description:
+ "Learn how to create an eye-catching Webflow popup contact form in minutes. Boost engagement, capture leads, and enhance your website",
+ postedAt: new Date("2024-09-11"),
+};
+
+export const metadata = generateMetadata(post);
+
+export default (props) => ;
Want to capture leads without disrupting your website's sleek design? The **Webflow popup contact form** can boost engagement. It combines Webflow's elegant design capabilities with a functional lead generation system.
@@ -46,10 +54,10 @@ Don't forget the finishing touches:
;
WhatsApp Business lets you reach 2.2 billion potential customers with a single message. But why are businesses choosing this platform? From high engagement rates to automation features, WhatsApp Business transforms how companies connect with their audience.
diff --git a/apps/landing-page/src/app/blog/[slug]/tweet.css b/apps/landing-page/src/features/blog/assets/tweet.css
similarity index 100%
rename from apps/landing-page/src/app/blog/[slug]/tweet.css
rename to apps/landing-page/src/features/blog/assets/tweet.css
diff --git a/apps/landing-page/src/features/blog/components/Header.tsx b/apps/landing-page/src/features/blog/components/Header.tsx
new file mode 100644
index 0000000000..e58a7eb268
--- /dev/null
+++ b/apps/landing-page/src/features/blog/components/Header.tsx
@@ -0,0 +1,40 @@
+import { Heading, Stack, Text } from "@chakra-ui/react";
+
+export const formatDate = (date: string) => {
+ const currentDate = new Date().getTime();
+ const dateWithTimezone = date.includes("T") ? date : `${date}T00:00:00`;
+ const targetDate = new Date(dateWithTimezone).getTime();
+ const timeDifference = Math.abs(currentDate - targetDate);
+ const daysAgo = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
+
+ const fullDate = new Date(dateWithTimezone).toLocaleString("en-us", {
+ month: "long",
+ day: "numeric",
+ year: "numeric",
+ });
+
+ if (daysAgo < 1) {
+ return "Today";
+ }
+ if (daysAgo < 7) {
+ return `${fullDate} (${daysAgo}d ago)`;
+ }
+ if (daysAgo < 30) {
+ const weeksAgo = Math.floor(daysAgo / 7);
+ return `${fullDate} (${weeksAgo}w ago)`;
+ }
+ if (daysAgo < 365) {
+ const monthsAgo = Math.floor(daysAgo / 30);
+ return `${fullDate} (${monthsAgo}mo ago)`;
+ }
+ const yearsAgo = Math.floor(daysAgo / 365);
+ return `${fullDate} (${yearsAgo}y ago)`;
+};
+
+type Props = { children: string; date: string };
+export const Header = ({ children, date }: Props) => (
+
+ {children}
+ {formatDate(date)}
+
+);
diff --git a/apps/landing-page/src/features/blog/components/Post.tsx b/apps/landing-page/src/features/blog/components/Post.tsx
new file mode 100644
index 0000000000..7846b06d66
--- /dev/null
+++ b/apps/landing-page/src/features/blog/components/Post.tsx
@@ -0,0 +1,48 @@
+import { Heading, Stack, Text } from "@chakra-ui/react";
+import type { PropsWithChildren } from "react";
+import type { BlogPostModel } from "../types";
+import "@/assets/prose.css";
+
+export type PostViewProps = PropsWithChildren<{
+ post: BlogPostModel;
+}>;
+
+export default function Post(props: PostViewProps) {
+ return (
+
+
+
+
+ {props.post.title}
+
+
+ {props.post.postedAt?.toLocaleDateString("en-US", {
+ day: "numeric",
+ month: "long",
+ year: "numeric",
+ timeZone: "UTC",
+ })}
+
+
+ {props.children}
+
+
+ );
+}
diff --git a/apps/landing-page/src/app/blog/Posts.tsx b/apps/landing-page/src/features/blog/components/Posts.tsx
similarity index 66%
rename from apps/landing-page/src/app/blog/Posts.tsx
rename to apps/landing-page/src/features/blog/components/Posts.tsx
index 866f58682a..ca12c2bb95 100644
--- a/apps/landing-page/src/app/blog/Posts.tsx
+++ b/apps/landing-page/src/features/blog/components/Posts.tsx
@@ -1,18 +1,14 @@
"use client";
import { Link } from "@chakra-ui/next-js";
import { Heading, Stack, Text } from "@chakra-ui/react";
+import { isDefined } from "@typebot.io/lib/utils";
+import type { BlogPost } from "../types";
type Props = {
- allBlogs: {
- metadata: {
- title: string;
- publishedAt: string;
- };
- slug: string;
- }[];
+ posts: BlogPost[];
};
-export const Posts = ({ allBlogs }: Props) => (
+export const Posts = ({ posts }: Props) => (
(
>
Latest blog posts:
- {allBlogs
- .filter((post) => post.metadata.publishedAt)
+ {posts
+ .filter((post) => isDefined(post.postedAt))
.sort((a, b) => {
- if (
- new Date(a.metadata.publishedAt) > new Date(b.metadata.publishedAt)
- ) {
+ if (new Date(a.postedAt!) > new Date(b.postedAt!)) {
return -1;
}
return 1;
@@ -43,10 +37,10 @@ export const Posts = ({ allBlogs }: Props) => (
p="4"
>
- {post.metadata.title}
+ {post.title}
- {new Date(post.metadata.publishedAt).toDateString()}
+ {new Date(post.postedAt!).toDateString()}
diff --git a/apps/landing-page/src/app/blog/[slug]/Table.tsx b/apps/landing-page/src/features/blog/components/Table.tsx
similarity index 100%
rename from apps/landing-page/src/app/blog/[slug]/Table.tsx
rename to apps/landing-page/src/features/blog/components/Table.tsx
diff --git a/apps/landing-page/src/app/blog/[slug]/Tweet.tsx b/apps/landing-page/src/features/blog/components/Tweet.tsx
similarity index 96%
rename from apps/landing-page/src/app/blog/[slug]/Tweet.tsx
rename to apps/landing-page/src/features/blog/components/Tweet.tsx
index 1f6b5e085d..6b9f71fa4c 100644
--- a/apps/landing-page/src/app/blog/[slug]/Tweet.tsx
+++ b/apps/landing-page/src/features/blog/components/Tweet.tsx
@@ -1,6 +1,6 @@
import { EmbeddedTweet, TweetNotFound, type TweetProps } from "react-tweet";
import { getTweet } from "react-tweet/api";
-import "./tweet.css";
+import "../assets/tweet.css";
const TweetContent = async ({ id, components, onError }: TweetProps) => {
let error;
diff --git a/apps/landing-page/src/features/blog/components/chakraClientComponents.ts b/apps/landing-page/src/features/blog/components/chakraClientComponents.ts
new file mode 100644
index 0000000000..22def5faee
--- /dev/null
+++ b/apps/landing-page/src/features/blog/components/chakraClientComponents.ts
@@ -0,0 +1,5 @@
+"use client";
+import { Link } from "@chakra-ui/next-js";
+import { Alert, AlertIcon, AlertTitle, Heading } from "@chakra-ui/react";
+
+export { Heading, Link, Alert, AlertIcon, AlertTitle };
diff --git a/apps/landing-page/src/features/blog/helpers.ts b/apps/landing-page/src/features/blog/helpers.ts
new file mode 100644
index 0000000000..fdcec6ed19
--- /dev/null
+++ b/apps/landing-page/src/features/blog/helpers.ts
@@ -0,0 +1,26 @@
+import { env } from "@typebot.io/env";
+import type { BlogPost } from "./types";
+
+export const generateMetadata = (post: BlogPost) => {
+ const ogImage = "";
+ return {
+ title: post.title,
+ description: post.description,
+ openGraph: {
+ type: "article",
+ publishedTime: post.postedAt?.toISOString(),
+ url: `${env.LANDING_PAGE_URL}/blog/${post.slug}`,
+ images: [
+ {
+ url: ogImage,
+ },
+ ],
+ },
+ twitter: {
+ card: "summary_large_image",
+ title: post.title,
+ description: post.description,
+ images: [ogImage],
+ },
+ };
+};
diff --git a/apps/landing-page/src/features/blog/types.ts b/apps/landing-page/src/features/blog/types.ts
new file mode 100644
index 0000000000..01fbf415b8
--- /dev/null
+++ b/apps/landing-page/src/features/blog/types.ts
@@ -0,0 +1,10 @@
+export interface BlogPostModel {
+ title: string;
+ description: string;
+ author: string;
+ postedAt?: Date;
+}
+
+export interface BlogPost extends BlogPostModel {
+ slug: string;
+}
diff --git a/apps/landing-page/src/mdx-components.tsx b/apps/landing-page/src/mdx-components.tsx
new file mode 100644
index 0000000000..486167c4d1
--- /dev/null
+++ b/apps/landing-page/src/mdx-components.tsx
@@ -0,0 +1,135 @@
+import { EndCta } from "@/components/Homepage/EndCta";
+import type { AlertProps } from "@chakra-ui/react";
+import { Standard } from "@typebot.io/nextjs";
+import type { MDXComponents } from "mdx/types";
+import Image from "next/image";
+import { highlight } from "sugar-high";
+import { Header } from "./features/blog/components/Header";
+import { Table } from "./features/blog/components/Table";
+import { Tweet } from "./features/blog/components/Tweet";
+import {
+ Alert,
+ AlertIcon,
+ AlertTitle,
+ Heading,
+ Link,
+} from "./features/blog/components/chakraClientComponents";
+
+const components: MDXComponents = {
+ h1: (props) => ,
+ h2: (props) => ,
+ h3: (props) => ,
+ h4: (props) => ,
+ h5: (props) => ,
+ h6: (props) => ,
+ code: ({ children, ...props }) => {
+ if (!props.className || props.className?.includes("md"))
+ return {children};
+ const hightlightedCode = highlight(children?.toString() ?? "");
+ return (
+
+ );
+ },
+ link: (props: any) => ,
+ Image: (props) => (
+
+ ),
+ Callout: ({ children, title, ...props }: AlertProps) => (
+
+
+ {title ? {title} : null}
+ {children}
+
+ ),
+ Tweet,
+ Typebot: (props: any) => (
+
+ ),
+ Youtube: ({ id }: { id: string }) => (
+