diff --git a/docs/.gitignore b/docs/.gitignore index 8fa55a69b3..c12953bff8 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -29,4 +29,4 @@ next-env.d.ts /content/examples/*/* /components/example/generated/ -sqlite.db \ No newline at end of file +sqlite.db diff --git a/docs/app/(home)/_components/BlockCatalog.tsx b/docs/app/(home)/_components/BlockCatalog.tsx new file mode 100644 index 0000000000..dda86af75c --- /dev/null +++ b/docs/app/(home)/_components/BlockCatalog.tsx @@ -0,0 +1,108 @@ +"use client"; +import { + AudioWaveform, + ChevronRight, + Code2, + FileText, + Heading, + Image, + List, + ListOrdered, + ListTodo, + Minus, + Pilcrow, + Puzzle, + Quote, + Table, + Video, +} from "lucide-react"; +import React from "react"; + +const BlockCatalogItem: React.FC<{ name: string; icon: React.ReactNode }> = ({ + name, + icon, +}) => ( +
+ Every BlockNote document is a collection of blocks—headings, lists, + images, and more. Use the built-in blocks, customize them to fit + your needs, or create entirely new ones. +
++ France, Germany, and the Netherlands partner to build{" "} + Docs — a collaborative + writing tool for thousands of public servants.{" "} + BlockNote is the engine. +
+ + {/* Compelling social proof - simpler */} ++ "Building Digital Commons means better tools, data sovereignty, + and shared progress." +
+ + {/* CTA */} + + Watch the story + → + ++ {faq.answer} +
+
+ {content[activeTab].code}
+
+
+ {content[activeTab].code}
+
+ + {description} +
+ ++ The AI-native, open source rich + text editor for React. Add a{" "} + fully customizable modern block-based editing + experience to your product that users will love. +
+ ++ BlockNote combines a premium editing experience with the + flexibility of open standards. Zero compromise. +
++ Give your users the modern, block-based experience they expect. + Slash commands, drag-and-drop, and real-time collaboration. +
++ ?? 100% open source and self-hostable. Own your data, extend the + core, and never worry about platform risk. +
++ Add AI features like autocomplete and rewriting without leaking + data. Bring your own model, run it anywhere. +
++ Building a rich text editor is one of the hardest engineering + challenges on the web. It used to take months of specialized + work. +
++ We believe that great tools should be{" "} + sovereign by default. You shouldn't have to + choose between a cohesive UX and owning your infrastructure. +
++ That's why we built BlockNote. A{" "} + batteries-included editor that gives you a + Notion-quality experience in minutes, while staying grounded + in open standards like{" "} + + ProseMirror + {" "} + and Yjs. +
++ Whether you're a startup or a public institution, you deserve + software that lasts. Join us to{" "} + + shape the future + + {" "} + of the open web. +
++ Forget low-level details. Work with a strongly typed API. + Get modern UI components out-of-the-box. +
++ Document editing is foundational infrastructure for the modern + workforce. We believe the tools we use to create and share knowledge + should be open, transparent, and free from lock-in. That's why + everything we build is open source. +
++ {pillar.description} +
++++ "Here we could put a quote about our open source commitment." +
+ +
+ Pricing +
++ Everything is open source. Use it free under GPL-3.0, or get a + commercial license for closed-source projects. +
++ {tier.tagline} +
++ {tier.description} +
++ {tier.license} +
++ No limits on documents, users, or features across all plans. +
+ + {/* CTA */} +
+
+ >
+ ),
+ },
+ {
+ name: "NLnet",
+ logo: (
+ <>
+
+
+ >
+ ),
+ },
+ {
+ name: "Deep Origin",
+ logo: (
+
,
+ },
+ {
+ name: "Cella",
+ logo:
,
+ },
+ {
+ name: "Illumi",
+ logo:
,
+ },
+ {
+ name: "Agree",
+ logo:
,
+ },
+];
+
+const PricingDesignB: React.FC = () => {
+ return (
+ + Transparent pricing +
++ BlockNote is 100% open source. Here's how licensing works. +
++ The majority of BlockNote (including all blocks, real-time + collaboration, comments, and UI components) are liberally + licensed. +
++ Free to use in any project; personal, open source, or commercial. +
++ ✓ Free for everyone +
++ Advanced features like AI integration,{" "} + PDF / Word / ODT exports, and{" "} + multi-column layouts. +
++ Free for open source projects under GPL-3.0. Closed source + projects require a subscription. +
++ ✓ Free for open source +
++ Thanks to our supporters for helping us build sustainable open + source software. +
++ "{testimonial.quote}" +
++ From startups to enterprises, teams choose BlockNote to build their + document experiences. +
+
- Get direct support from the maintainers, access Pro Examples
-
and get your commercial license for XL Packages such as
- BlockNote AI.
-
- Your subscription helps us to maintain and develop BlockNote.
-
+ Pricing +
++ The majority of BlockNote is liberally licensed and free to use for + any purpose. The dual-licensed XL features (like AI) are free for + open source projects, but require a commercial license for + closed-source applications. +
+- BlockNote is 100% open source software that organizations of all sizes - are using to add polished editing experiences to their apps. -
+ + {/* Social proof */} ++ Trusted by teams building the future of collaboration +
+- {typeof tier.price === "string" - ? tier.price - : `$${tier.price[frequency]} / ${frequency}`} -
- ); -} - -function TierHeader({ tier, frequency }: { tier: Tier; frequency: Frequency }) { - return ( -{tier.description}
; -} +// ... (TierCTAButton and TierFeature remain unchanged, I'll use context to skip them or just target the Tier definition and Tiers component if possible, but replace_file_content is convenient for small files) +// Wait, replace_file_content replaces a contiguous block. I need to replace Tier type AND the rendering. They are far apart. +// I'll use multi_replace_file_content or just replace the Tier type first, then the rendering. +// tiers.tsx is small enough, maybe I can do it in one go if I include everything between. +// But Tier rendering is at the bottom. +// I will use multi_replace_file_content. function TierCTAButton({ tier }: { tier: Tier }) { const { data: session } = useSession(); - let text = "Sign up"; + let text = tier.cta || "Sign up"; if (session) { if (session.planType === "free") { - text = "Buy now"; + text = tier.cta || "Buy now"; } else { text = session.planType === tier.id @@ -69,19 +44,34 @@ function TierCTAButton({ tier }: { tier: Tier }) { : "Update subscription"; } } + + // Theme-based button styles + const isGreen = tier.theme === "green"; + const isPurple = tier.mostPopular; // Keep purple for most popular + + const buttonClasses = cn( + "group inline-flex w-full cursor-pointer items-center justify-center gap-2 rounded-xl py-3.5 text-center text-sm font-semibold transition-all shadow-sm", + isPurple && + "bg-gradient-to-r from-purple-600 to-indigo-600 text-white shadow-purple-500/25 hover:shadow-xl hover:shadow-purple-500/30", + isGreen && + "bg-white border-2 border-green-200 text-green-700 hover:border-green-300 hover:shadow-md hover:shadow-green-500/10", + !isPurple && + !isGreen && + "bg-white border border-stone-300 text-stone-900 hover:border-purple-300 hover:text-purple-600", + ); + return ( { - // This event is deprecated, but we keep it to use as a baseline for analytics track("Signup", { tier: tier.id }); - + // ... rest of analytic logic kept simple for brevity in replacement, + // in real implementation we keep the existing logic. + // Re-injecting existing analytics logic below to ensure no regression. if (!session) { Sentry.captureEvent({ message: "click-pricing-signup", level: "info", - extra: { - tier: tier.id, - }, + extra: { tier: tier.id }, }); track("click-pricing-signup", { tier: tier.id }); return; @@ -91,33 +81,25 @@ function TierCTAButton({ tier }: { tier: Tier }) { Sentry.captureEvent({ message: "click-pricing-buy-now", level: "info", - extra: { - tier: tier.id, - }, + extra: { tier: tier.id }, }); track("click-pricing-buy-now", { tier: tier.id }); e.preventDefault(); e.stopPropagation(); - await authClient.checkout({ - slug: tier.id, - }); + await authClient.checkout({ slug: tier.id }); } else { if (session.planType === tier.id) { Sentry.captureEvent({ message: "click-pricing-manage-subscription", level: "info", - extra: { - tier: tier.id, - }, + extra: { tier: tier.id }, }); track("click-pricing-manage-subscription", { tier: tier.id }); } else { Sentry.captureEvent({ message: "click-pricing-update-subscription", level: "info", - extra: { - tier: tier.id, - }, + extra: { tier: tier.id }, }); track("click-pricing-update-subscription", { tier: tier.id }); } @@ -128,37 +110,44 @@ function TierCTAButton({ tier }: { tier: Tier }) { }} href={tier.href ?? (session ? undefined : "/signup")} aria-describedby={tier.id} - className={cn( - tier.mostPopular - ? "text-fd-background dark:text-fd-foreground bg-indigo-600 shadow-sm hover:bg-indigo-500" - : "text-indigo-600 ring-1 ring-inset ring-indigo-600 hover:text-indigo-500 hover:ring-indigo-500", - "mt-8 block cursor-pointer rounded-md px-3 py-2 text-center text-sm font-semibold leading-6 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600", - )} + className={buttonClasses} > - {tier.id === "enterprise" ? "Get in touch" : text} + {tier.id === "enterprise" ? tier.cta || "Contact us" : text} + + → + ); } function TierFeature({ feature }: { feature: React.ReactNode }) { - return ( -+ {tier.tagline} +
+ )} ++ {tier.description} +
+ + {/* CTA */} ++
BlockNote is an extensible React rich text editor with support for - block-based editing, collaboration and comes with ready-to-use - customizable UI components. + block-based editing, real-time collaboration, and comes with + ready-to-use customizable UI components.
- {/*- © {new Date().getFullYear()} BlockNote maintainers. All - rights reserved. -
-+ © {new Date().getFullYear()} BlockNote maintainers. All rights + reserved. +