Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Image upload #6

Open
fasthold opened this issue May 22, 2024 · 7 comments
Open

Feature Request: Image upload #6

fasthold opened this issue May 22, 2024 · 7 comments

Comments

@fasthold
Copy link

Editor lacks of image uploading function, it's an essential feature in rich editing.

Wish this will be shown in the demo example.

Thanks.

@avioli
Copy link

avioli commented May 26, 2024

Image uploading is a tight integration process between the back-end and a front-end. This library (as well as TipTap) are front-end only libraries. They do not know how to upload to a server and that process can be as diverse as it gets.

Best that can be done by a front-end library is image insertion from a URL and then styling that with different styles and crops.

Keep in mind that Gutenberg is a library that has super-tight-integration with WordPress and the image upload process is very well known in comparison to this library, which doesn't assume what server architecture you have.

You can enable <img> elements by adding the Image extension and then have it in the :extensions="[Image]" prop. Then you need to create a block/inline tool to suit your back-end needs that can upload to your server and finally you can use the resulting url to insert the image into the editor:

  editor
    .chain()
    .focus()
    .setImage({
      src: url,
      alt: alt || undefined,
      title: title || undefined,
    })
    .run();

Having said all that - my latest project's server is on Directus, and my front-end is on Nuxt, so I can add a file upload input that is scoped to certain file types, then handle the upload when the user picks a file and the server gives me a file object:

<script setup lang="ts">
const props = defineProps<{
  editor: Editor;
}>();

const input = ref<HTMLInputElement | null>(null);

const assetsBase = "https://api.myserver/assets";

const handleFiles = async () => {
  const { files } = input.value || {};
  const [first] = files || [];
  if (first) {
    const data = new FormData();
    data.append("file", first, first.name);
    const result = await useDirectus<DirectusFiles>(uploadFiles(data));
    const { id, title } = result;
    const url = `${assetsBase}/${id}`;
    props.editor.chain().focus().setImage({ src: url, alt: title || undefined, title: title || undefined }).run();
  }
};
</script>

<template>
  <!-- other stuff like show preview of previous upload and wrap the input below, since it is visually hidden -->
  <input
    ref="input"
    accept=".jpg,.jpeg"
    type="file"
    class="absolute inset-0 z-[2] w-full cursor-pointer appearance-none border-none opacity-0 focus:outline-none"
    @change="handleFiles"
  />
  <!-- other stuff like upload button, upload progress, errors, deletion -->
</template>

As you can see - my process is most probably super specific to my needs and cannot be applied for everyone.

@avioli
Copy link

avioli commented May 26, 2024

@johnpuddephatt - I wonder if the demo can show use of an Image by simply asking for a URL.

@avioli
Copy link

avioli commented May 26, 2024

@fasthold Alternatively you can use an upload image extension like this one: https://github.com/carlosvaldesweb/tiptap-extension-upload-image

@johnpuddephatt
Copy link
Owner

Agree with both of you! Like @avioli says it is project specific, but we should show a couple of examples in the demo – perhaps the tiptap extension linked to plus a custom solution using a Vue component that uses something like FilePond as I think this will demonstrate how easy it is to do something custom.

@avioli
Copy link

avioli commented Jun 13, 2024

@johnpuddephatt That's a very good idea, although I've used FilePond in a couple of projects and I'm not sure it will work great within a contenteditable area, but I'll be happy to be proven wrong!

@eguvenc
Copy link

eguvenc commented Dec 14, 2024

What about the image files encode immediately as base64 img src. This can fix the upload problem. And it's serverless. ?

@avioli
Copy link

avioli commented Dec 16, 2024

@eguvenc It is an option, but base64 is inherently making binary files take larger space, because they are limited to a smaller sub-set of characters.

From StackOverflow:

Base64 encodes each set of three bytes into four bytes. In addition the output is padded to always be a multiple of four.

This means that the size of the base-64 representation of a string of size n is:

ceil(n / 3) * 4
So, for a 16kB array, the base-64 representation will be ceil(16*1024/3)*4 = 21848 bytes long ~= 21.8kB.

A rough approximation would be that the size of the data is increased to 4/3 of the original.

So a 1 MB file would become 1.3 MB, 5 MB => 6.67 MB, 10 MB => 13.3 MB

The file will be embedded into the resulting HTML, or JSON. It really depends what you want to achieve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants