npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

another-novel-svelte

v1.2.0

Published

Heavily biased Notion-style WYSIWYG editor without the bells and whistles.

Downloads

9

Readme

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

| Prop | Type | Default | Description | |------|------|---------|-------------| | class | string | '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 | | defaultValue | JSONContent \| string | defaultEditorContent | The default value to use for the editor | | extensions | Extension[] | [] | Additional extensions to use for the editor | | editorProps | EditorProps | {} | Additional props to pass to the Tiptap editor | | onUpdate | (editor?: Editor) => void \| Promise<void> | noop | Callback function called on every editor update | | onDebouncedUpdate | (editor?: Editor) => void \| Promise<void> | noop | Callback function called after debounce duration | | debounceDuration | number | 750 | Duration to debounce the onDebouncedUpdate callback | | storageKey | string | 'novel__content' | Key to use for storing editor content in localStorage | | disableLocalStorage | boolean | false | Disable local storage read/save | | imageProviderConfig | UploadConfig \| undefined | undefined | Configuration for image upload provider |

Contributing

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

License

MIT License