This documentation is for a legacy version of Next.js and Supabase. For the latest version, please visit the Next.js and Supabase V2 documentation

AI Text Editor Plugin for the Next.js Supabase Saas Starter Kit

This plugin adds an AI WYSIWYG Editor to your Next.js Supabase SaaS application.

This plugin adds an AI Editor component Next.js application. You can import this component anywhere in your application.

It is built with Lexical, a text editor framework for React, by Meta.

This plugin is currently experimental and not yet officially released.

Using the Plugin

Installation

To install the plugin, you can use git subtrees from your original repository:

git subtree add --prefix plugins/text-editor git@github.com:makerkit/next-supabase-saas-kit-plugins.git text-editor --squash

After running this command, you will have the plugin in your repository at plugins/text-editor. Once pulled, you can apply any customization you need.

Using the CLI

If you're using the CLI, you can run the following command to install the plugin:

npx @makerkit/cli@latest plugins install

Follow the instructions to install the plugin.

Add the plugin as a workspace in your package.json

You can do so by adding the following to your package.json file:

{
"workspaces": [
"plugins/text-editor"
]
}

Add it next to the other workspaces in your package.json file.

Add the paths alias to the TypeScript configuration

To make sure that the TypeScript compiler can find the plugin, you will need to add the following paths alias to your tsconfig.json file, in addition to the other paths aliases that you may have.

If not yet present, add the following to your tsconfig.json file:

{
"compilerOptions": {
"paths": {
"~/plugins/*": [
"./plugins/*"
]
}
}
}

You only need to add this once, even if you have multiple plugins.

Installing dependencies

To install the dependencies, you can run the following command:

npm i

NPM will install the dependencies in the plugins/text-editor folder as an NPM workspace.

Add the required API handlers

You will need to add the following API handlers to your application:

  • api/ai/autocomplete/route.ts
  • api/ai/edit/route.ts

Edit Route

To add the edit route, create a file at src/app/api/ai/edit/route.ts with the following content:

import { createAIEditRouteHandler } from '~/plugins/text-editor/lib/route-handler';
export const runtime = `edge`;
export const POST = createAIEditRouteHandler;

Autocomplete Route

To add the autocomplete route, create a file at src/app/api/ai/autocomplete/route.ts with the following content:

import { createAIAutocompleteRouteHandler } from '~/plugins/text-editor/lib/route-handler';
export const runtime = `edge`;
export const POST = createAIAutocompleteRouteHandler;

Style

Import the CSS file at plugins/text-editor/editor.css into your global CSS file at src/app/styles/globals.css:

@import "../../plugins/text-editor/editor.css";

Using the plugin

To use the plugin, you can import the component from the plugin folder.

NB: the example below uses rxjs, which is a dependency not included in the kit. I do recommend using it, but you can use any other library to handle debouncing and other logic that you may need if you want to use autosaving for your application.

'use client';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { toast } from 'sonner';
import {
debounceTime,
distinctUntilChanged,
Subject,
switchMap,
tap,
} from 'rxjs';
import Editor from '~/plugins/text-editor/components/Editor';
export default function EditorContainer() {
const subject$ = useMemo(() => new Subject(), []);
const currentToastId = useRef<string | number>();
const onChange = useCallback(
(content: string) => {
subject$.next(content);
},
[subject$],
);
useEffect(() => {
const subscription = subject$
.pipe(
debounceTime(2000),
distinctUntilChanged(),
switchMap(() => {
if (currentToastId.current) {
toast.dismiss(currentToastId.current);
}
currentToastId.current = toast.loading('Saving...', {
id: currentToastId.current,
});
return new Promise((resolve) => {
setTimeout(resolve, 2000);
});
}),
tap(() => {
toast.success('Saved!', {
id: currentToastId.current,
});
}),
)
.subscribe(() => {
currentToastId.current = undefined;
});
return () => {
subscription.unsubscribe();
};
}, [subject$]);
return (
<>
<Editor
className={'h-[80vh] w-[100vh]'}
content={getInitialContent()}
onChange={onChange}
/>
</>
);
}
function getInitialContent() {
return `
## Introducing Makerkit's AI Editor
This plugin is powered by OpenAI's GPT-3 and Lexical's Editor, and helps you add an AI-powered editor to your SaaS, in just a few lines of code.
Install it using the CLI:
\`\`\`
npx @makerkit/cli plugins install
\`\`\`
Available for *Pro* and *Teams* customers **for free**.
`.trim();
}

Now, import the component EditorContainer anywhere in your application:

import { Toaster } from 'sonner';
import dynamic from 'next/dynamic';
import PageLoadingIndicator from '~/core/ui/PageLoadingIndicator';
import { withI18n } from '~/i18n/with-i18n';
import I18nProvider from '~/i18n/I18nProvider';
import getLanguageCookie from '~/i18n/get-language-cookie';
const EditorContainer = dynamic(
() => {
return import('~/app/editor/EditorContainer');
},
{
ssr: false,
loading: () => (
<PageLoadingIndicator fullPage={false}>Loading...</PageLoadingIndicator>
),
},
);
function EditorPage() {
return (
<I18nProvider lang={getLanguageCookie()}>
<div
className={
'w-screen h-screen flex justify-center items-center bg-gray-50' +
' dark:bg-dark-900 flex flex-col space-y-4'
}
>
<Toaster />
<EditorContainer />
</div>
</I18nProvider>
);
}
export default withI18n(EditorPage);