1.2.0 • Published 9 months ago

another-novel-svelte v1.2.0

Weekly downloads
-
License
MIT
Repository
github
Last release
9 months ago

Novella Svelte

Heavily biased Notion-style WYSIWYG editor without the bells and whistles. I'm maintaining this for my blogging website called AcademiaScribes.

Based on Novel

Forked from Novel-Svelte

Made for DennisOluoch

Features

  • šŸ“ Rich Text Editor with Notion-style formatting
  • šŸ–¼ļø Image uploads with drag & drop, paste, and file selection
  • šŸ’¾ Auto-saving to local storage
  • ⚔ Lightning fast and lightweight
  • šŸŽØ Fully customizable with Tailwind CSS
  • šŸ“± Mobile-friendly and responsive

Techs and Works

  • Svelte - Frontend framework
  • Tiptap - Headless editor framework
  • Tailwind CSS - Styling

Installation

npm i another-novel-svelte

Basic Usage

<script>
    import { Editor } from 'another-novel-svelte';

    let saveStatus = 'Saved';
    let editor;

    // Image upload configuration
    const imageProviderConfig = {
        provider: 'vercel',
        bucketName: 'your-bucket-name',
        accessToken: 'your-access-token'
    };
</script>

<main>
    <Editor
        bind:editor
        {imageProviderConfig}
        onUpdate={() => {
            saveStatus = 'Unsaved';
        }}
        onDebouncedUpdate={() => {
            saveStatus = 'Saving...';
            // Saving code goes here
            saveStatus = 'Saved';
        }}
    >
        <div>
            {saveStatus}
        </div>
    </Editor>
</main>

Image Upload Configuration

The editor supports image uploads to multiple providers: Vercel Blob, Supabase Storage, and Cloudinary. Instead of using environment variables, we now pass the configuration directly to the Editor component.

Configuration Setup

Create a configuration object in your Svelte component:

const imageProviderConfig = {
    provider: 'vercel', // Options: 'vercel', 'supabase', 'cloudinary'
    bucketName: 'your-bucket-name',
    accessToken: 'your-access-token',
    // Additional properties based on the provider:
    // For Supabase:
    // supabaseUrl: 'your-project-url'
    // For Cloudinary:
    // cloudinaryCloudName: 'your-cloud-name'
};

Then pass this configuration to the Editor component:

<Editor {imageProviderConfig} ...otherProps>
    <!-- Editor content -->
</Editor>

Provider Setup Instructions

Vercel Blob

  1. Set up a Vercel project
  2. Get your Blob access token from the Vercel dashboard
  3. Configure the imageProviderConfig as shown above

Supabase Storage

  1. Create a Supabase project
  2. Create a storage bucket
  3. Set the storage bucket to public if you want the images to be publicly accessible
  4. Get your service role key from the project settings
  5. Configure the imageProviderConfig as shown above, including the supabaseUrl

Cloudinary

  1. Create a Cloudinary account
  2. Create an upload preset (can be done in the Settings > Upload section)
  3. Get your cloud name and API credentials
  4. Configure the imageProviderConfig as shown above, including the cloudinaryCloudName

Image Upload Features

  • šŸ“¤ Drag and drop image uploads
  • šŸ“‹ Paste images directly from clipboard
  • šŸ–¼ļø Support for all standard image formats (jpg, png, gif, etc.)
  • āš–ļø Maximum file size: 20MB
  • šŸ”„ Real-time upload status with toast notifications
  • šŸ“ Image resizing after upload
  • šŸ’¾ Automatic image optimization

Security Considerations

āš ļø Important: The configuration passed to the Editor component will be visible in the client-side code. For production use, we strongly recommend implementing a server-side API endpoint to handle the actual upload operations.

Recommended Production Setup

  1. Create a server-side API endpoint (using SvelteKit or your preferred backend):
// routes/api/upload/+server.ts
import { json } from '@sveltejs/kit';

export async function POST({ request }) {
    const file = await request.blob();
    // Handle upload using server-side tokens
    // Return the URL of the uploaded file
    return json({ url: uploadedUrl });
}
  1. Use the server endpoint in production:
const uploadFile = async (file: File) => {
    if (import.meta.env.DEV) {
        // Use direct provider upload in development
        return handleDirectUpload(file);
    } else {
        // Use server endpoint in production
        const formData = new FormData();
        formData.append('file', file);
        const response = await fetch('/api/upload', {
            method: 'POST',
            body: formData
        });
        const { url } = await response.json();
        return url;
    }
};

Development

  1. Install Node.js and npm (download here)

  2. Clone the repository:

git clone https://github.com/DennisOluoch/novel-svelte.git
cd novel-svelte
  1. Install dependencies:
npm install
  1. Start the development server:
npm run dev

Visit http://localhost:5173/ to see the preview.

Props

PropTypeDefaultDescription
classstring'relative min-h-[500px] w-full max-w-screen-lg border-stone-200 bg-white p-12 px-8 sm:mb-[calc(20vh)] sm:rounded-lg sm:border sm:px-12 sm:shadow-lg'Additional classes to add to the editor container
defaultValueJSONContent \| stringdefaultEditorContentThe default value to use for the editor
extensionsExtension[][]Additional extensions to use for the editor
editorPropsEditorProps{}Additional props to pass to the Tiptap editor
onUpdate(editor?: Editor) => void \| Promise<void>noopCallback function called on every editor update
onDebouncedUpdate(editor?: Editor) => void \| Promise<void>noopCallback function called after debounce duration
debounceDurationnumber750Duration to debounce the onDebouncedUpdate callback
storageKeystring'novel__content'Key to use for storing editor content in localStorage
disableLocalStoragebooleanfalseDisable local storage read/save
imageProviderConfigUploadConfig \| undefinedundefinedConfiguration for image upload provider

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License