uiwjs / react-md-editor

A simple markdown editor with preview, implemented with React.js and TypeScript.
https://uiwjs.github.io/react-md-editor
MIT License
2.19k stars 160 forks source link

why adding embedded video cause showing html tags ? like a code ? #471

Closed am0029 closed 1 year ago

am0029 commented 1 year ago

why adding embedded video cause showing html tags ? like a code ?

jaywcjlove commented 1 year ago

@am0029 use rehype-video

import rehypeVideo from 'rehype-video';

<MDEditor
  value={value}
  onChange={setValue}
  previewOptions={{
    rehypePlugins: [[rehypeVideo]],
  }}
/>
jaywcjlove commented 1 year ago

@am0029 or use remark-oembed

import rehypeOembed from 'remark-oembed';

<MDEditor
  value={value}
  onChange={setValue}
  previewOptions={{
    rehypePlugins: [[rehypeOembed]],
  }}
/>
am0029 commented 1 year ago

thanks but none of them working both give error in their node module folder . did u test this ? please say

import rehypeOembed from 'remark-oembed';

it said there is no remark-oembed and for both of them same error even after i follow their documentation and install both of them

it is wired error

my error is releated to this person

https://github.com/remarkjs/remark/discussions/742

this 2 ithink is async or something like that and can not added into mde ? is this true? what is soloution ?

jaywcjlove commented 1 year ago

@am0029 https://codesandbox.io/embed/markdown-editor-for-react-https-github-com-uiwjs-react-md-editor-issues-471-v91bp1?fontsize=14&hidenavigation=1&theme=dark

image

@am0029

am0029 commented 1 year ago

thanks but why not showing after post it seems not sending setBody and body right .

see thease pictures for me it is ok when u want write in editor

but after u post it just show that plaintext html tags

i mean in preview mode is ok showing the video but after sending body to server . this just showing plain text or html tags

is it possible mde does not recognize plugins ? or problem it just server side

can u see pictures

this picture is when posting

https://postimg.cc/VSJQr1NR

and this after posting just plain html tag in website

https://postimg.cc/K1vybtSC

can u help me sir

https://i.postimg.cc/NFy2YHQy/333.png https://i.postimg.cc/4NW4wdGq/ccc.png

jaywcjlove commented 1 year ago

@am0029 Do you need a preview?

import React from "react";
import ReactDOM from "react-dom";
import MDEditor from "@uiw/react-md-editor";
import rehypeVideo from "rehype-video";

const mkdStr = `
# Markdown Editor

https://user-images.githubusercontent.com/1680273/138299599-88547edd-859c-44c9-8b52-2cc06f7f2dd3.mov?!#title=Example%20Display

`;

function App() {
  const [value, setValue] = React.useState(mkdStr);
  return (
    <div className="container">
      <MDEditor.Markdown
        style={{ padding: 15 }}
        source={value}
        linkTarget="_blank"
        rehypePlugins={[[rehypeVideo]]}
      />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("container"));
am0029 commented 1 year ago

do you know this is dev.to clone . people come to website and work with editor right ?

for example they want use embedded video right

in the editor show correctly . but after they submiting their post the mde editor just send htmls tags to website like this

https://i.postimg.cc/NFy2YHQy/333.png

see this is new.post code


// import { createEditor } from 'slate'
// import { Slate, Editable, withReact } from 'slate-react'
// import "easymde/dist/easymde.min.css";

// import React, { Component } from 'react';
import { rehype } from 'rehype';

import rehypeVideo from 'rehype-video';

import MDEditor from '@uiw/react-md-editor';

// import  {  useMemo } from "react";

// import SlateEditor from "./Editorr";
// import React, { useState, useRef } from "react";
import './NewPost.css'

// import SimpleMDE from "react-simplemde-editor";

import { useContext, useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import tw from 'twin.macro';
import Error from '../../common/Error';
import LoadingSpinner from '../../common/LoadingSpinner';
import RouteWrapper from '../../common/RouteWrapper';
import socketContext from '../../context/SocketContext';
import { selectCurrentUser } from '../../core/features/auth/authSlice';
import { useCreatePostMutation } from '../../core/features/posts/postsApiSlice';
import { useGetUserDashboardQuery } from '../../core/features/users/usersApiSlice';
import useBase64 from '../../hooks/useBase64';
import useRequireAuth from '../../hooks/useRequireAuth';
import { useMemo } from "react";
// import Appp from "./Editorr";
// import { Editor } from "react-draft-wysiwyg";
// import "../../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
// import React, { Component } from 'react';
// import "../NewPost/react-draft-wysiwyg.css"
// import "react-draft-wysiwyg/dist/react-draft-wysiwyg.cs";

// import LiveMarkdown from '../markdowneditor/markdowneditor';
// import  EasyMDE from 'easymde';
// const [editor] = useState(() => withReact(createEditor()))
const NewPost = () => {

  // const JoditEditor = {
  //   "defaultFontSizePoints": "pt",
  //   "uploader": {
  //     "insertImageAsBase64URI": true
  //   },
  //   "language": "fa",
  //   "toolbarButtonSize": "large",
  //   "defaultMode": "1",
  //   "minHeight": 400,
  //   "inline": true,
  //   "toolbarInlineForSelection": true,
  //   "showPlaceholder": false,
  //   "buttons": "bold,italic,underline,strikethrough,eraser,ul,ol,font,fontsize,paragraph,classSpan,lineHeight,superscript,subscript,file,image,video,speechRecognize,spellcheck"
  // };

  // const editor = useRef(null);
  // const config = useMemo ({
  //   readonly: false,
  //   height: 400,
  // });
  // const handleUpdate = (event) => {
  //   const editorContent = event.target.innerHTML;
  //   setBody(setBody);
  // };

  const [title, setTitle] = useState('');
  const [file, setFile] = useState('');
  // const [editorstate, setEditorstate] = useState('');
  const [body, setBody] = useState('');

  const [tags, setTags] = useState('');
  const [isTagsFocused, setIsTagsFocused] = useState(false);
  const [inputsFilled, setInputsFilled] = useState(false);
  const filePickerRef = useRef();
  const titleRef = useRef();
  const [createPost, { isLoading, isError }] = useCreatePostMutation();
  const navigate = useNavigate();
  const currentUser = useSelector(selectCurrentUser);
  const dispatch = useDispatch();
  const previewURL = useBase64(file);
  const { isAuthed, handleAuth } = useRequireAuth();
  const { socket } = useContext(socketContext);
  const { data: user } = useGetUserDashboardQuery(currentUser.username);

  useEffect(() => titleRef.current.focus(), []);

  useEffect(() => {
    if (title
      //  && file && body 
      && tags) setInputsFilled(true);
    else setInputsFilled(false);
  }, [title, file, body, tags]);

  const handleSubmit = async () => {
    if (inputsFilled) {
      if (isAuthed) {
        try {
          const { id } = await createPost({
            title,
            file: previewURL,
            body,
            tags,
            authorUsername: currentUser.username,
          }).unwrap();

          socket.emit('post', {
            sender: currentUser,
            receivers: user?.followers,
            post: { title, id },
          });

          setTitle('');
          setFile('');
          setBody('');
          setTags('');

          navigate('/');
        } catch (err) {
          console.log(err);
        }
      } else handleAuth();
    }
  };

  return (
    <RouteWrapper>
      <Wrapper>
        {isLoading && <LoadingSpinner />}
        {!isLoading && (
          <NewPostWrapper>
            <Heading>ایجاد پست جدید</Heading>
            <InputWrapper>
              <Label dir='rtl' htmlFor='title'>موضوع <p> دقت داشته باشید که موضوع بیشتر از 48 حرف نمیتواند باشد </p></Label>
              <Input
                maxLength={48}

                type="text"
                dir='rtl'
                ref={titleRef}
                id='title'
                value={title}
                onBlur={e => setTitle(prev => prev.trim())}
                onChange={e => setTitle(e.target.value)}
                required
              />
              <br></br>    <Label dir='rtl' htmlFor='title' ><p> عکس برای پست تان انتخاب نمایید . انتخاب عکس اجباری نمی باشد</p> </Label>

            </InputWrapper>
            <InputWrapper>
              <Input
                type='file'
                ref={filePickerRef}
                onChange={e => setFile(e.target.files[0])}
                style={{ display: 'none' }}

              />
              <ImagePreview src={previewURL.toString()} alt='' />
              <Button onClick={() => filePickerRef.current.click()}>انتخاب عکس</Button>
            </InputWrapper>

            {/* <p>متن خود را وارد نمایید <br /> برای اضافه کردن کد جاوااسکریپت به متن بدین شکل عمل کنید <br /> ```javascript 
 <br />محل قرار گیری کد جاوا اسکریپتی شما <br/>
```</p>             */}

            <InputWrapper2>

              {/* 1 */}

              {/* <SimpleMDE value={body} onChange={setBody} required /> */}

              {/* 2 */}
              {/* <Editor
              value={body}
                    // editorState={}
                    toolbarClassName="toolbarClassName"
                    wrapperClassName="wrapperClassName"
                    editorClassName="editorClassName"
                    onEditorStateChange={setBody}
                    textAlignment="right"
                    placeholder="اینجا تایپ کنید"
                />; */}

              {/* 3 */}

              <div className="md-editor-rtl ">
                <MDEditor
                  value={body}
                  style={{ padding: 15 }}
                  linkTarget="_blank"
                  onChange={setBody}
                  height={400}
                  rehypePlugins={[[rehypeVideo]]}
                  textareaProps={{
                    placeholder: "اینجا تایپ کنید",

                  }}
                  previewOptions={{
                    rehypePlugins: [[rehypeVideo]]
                  }}
                />
              </div>

              <p style={{ "color": "gray", "fontSize": "0.8rem" }}>      راهنما : در سمت چپ پیش نمایش پست خودتان را میتوانید ببینید . هنگام نوشتن کدهای برنامه نویسی ملاک سمت چپ میباشد.  همچنین برای اضافه کردن کد  به متن ابتدا کد خود را درون یک ویرایشگر متن مانند  Vs Code نوشته و سپس به شکل زیر درون ادیتور بالا پیست کنید <br /> <br /> &nbsp;&nbsp;```javascript
                <br />&nbsp;&nbsp;محل قرار گیری کد شما <br />
                &nbsp;&nbsp;```</p>     {/*  */}

              {/* <SlateEditor /> */}

              {/* <JoditEditor
        ref={editor}
        value={body}
        config={config}
        // onBlur={handleSubmit}
        handleSubmit={handleSubmit}
        onChange={setBody}
        required
      /> */}
              {/* <div dangerouslySetInnerHTML={{ __html: body }} /> */}

            </InputWrapper2>
            <InputWrapper>
              <Label htmlFor='tags'>
                تگ ها
                {isTagsFocused && (
                  <Span>تگ ها را با کاما(,) از یکدیگر جدا کنید </Span>
                )}
              </Label>
              <Input
                maxLength={15}
                id='tags'
                value={tags}
                onFocus={() => setIsTagsFocused(true)}
                onBlur={() => setIsTagsFocused(false)}
                onChange={e => setTags(e.target.value.replace(/ /g, ''))}
                required
              />
            </InputWrapper>
            <Submit onClick={handleSubmit}>تایید</Submit>
            {isError && <Error>خطاا در انجام عملیات . دوباره امتحان کنید . زمان کامپیوتر خود رابررسی کنید و فقط از آی پی ایران اقدام به ارسال پست بکنید </Error>}
            {!inputsFilled && <Error>تمام فیلدها اجباری هست . زمان تقریبی ارسال پست یک دقیقه میباشد . لطفا صبور باشید عکس پست تان آپلود شود </Error>}
          </NewPostWrapper>
        )}
      </Wrapper>
    </RouteWrapper>
  );
};

const Submit = tw.button`bg-lighter-gray hover:bg-light-gray rounded-md text-center py-2 px-1 w-full text-sm`;

const ImagePreview = tw.img`w-32 h-32 mx-auto border border-gray flex justify-center items-center text-center object-cover`;

const Input = tw.input`py-1 px-2 rounded-md outline-none border-2 border-solid border-gray focus:border-blue`;

const Label = tw.label`font-bold text-dark-gray`;

const Span = tw.p`inline ml-sm`;

const InputWrapper = tw.div`flex flex-col gap-2  `;

const Button = tw.button`bg-lighter-gray hover:bg-light-gray rounded-md text-center py-2 px-1 w-28 text-sm mx-auto`;

const Heading = tw.h1`text-dark-gray text-center`;

const NewPostWrapper = tw.div`bg-white w-3/5 mob:(w-full px-4) mx-auto py-20 px-8 [&>*:not(:last-child)]:mb-md`;

const Wrapper = tw.div`flex items-center`;

const InputWrapper2 = tw.div`border border-gray`;

export default NewPost;

`

can u help me please maybe the problem is the post.list and other part of website not the editor right ?

can u check my editor is ok ?
am0029 commented 1 year ago

sorry i am asking too question . i am just 40 years old man from middleeast

i know i am asking too much please help me

my problem is it shows correctly in markdown editor like u in codesandbox shows correctly but when sending value={body}

it just send string to server and html tag shows in website

but after users submit their post to the website

website just shows html tag

what is wrong ? should i use rehype in my post.body

can u see this file i am sure problem is not markdown is just this file can u check please

import { useNavigate } from 'react-router-dom';
import tw, { styled } from 'twin.macro';
import AuthorDetails from '../../../common/AuthorDetails';
import CustomMarkdown from '../../../common/CustomMarkdown';
import Tags from '../../../common/Tags';
import { formatDate } from '../../../helpers/string';
import Advertise from './Advertise';
import Comments from './Comments';
import './Post.css';
import { rehype } from 'rehype';
import rehypeVideo from 'rehype-video';

const Post = ({ post, isLaptop }) => {
  const navigate = useNavigate();

  const htmlStr = rehype(post.body)

  return (

    <Wrapper>
      <Image src={post?.image?.url}
       />
      {/* <div id="pos-article-display-78271"></div> */}
      <Advertise />
      <Content>
        <Header>
          <Author
            src={post.author.picture.url}
            onClick={() => navigate(`/${post.author.username}`)}
          />
          <AuthorMeta>
            <AuthorName>{post.author.name}</AuthorName>
            <CreatedAt>{formatDate(post.createdAt)}</CreatedAt>
            {formatDate(post.updatedAt) !== formatDate(post.createdAt) && (
              <UpdatedAt>{`Updated ${formatDate(post.updatedAt)}`}</UpdatedAt>
            )}
          </AuthorMeta>
        </Header>
        <Title>{post.title}</Title>

        <Tags tags={post.tags} isColored={true} />
           <div className="postbody"> <PostBody>
          <CustomMarkdown children={post.body} />
        </PostBody></div>
        <CommentsContainer>
          {post.comments && (
            <Comments postTitle={post.title} postAuthor={post.author} postId={post.id} />
          )}
        </CommentsContainer>
      </Content>
      {isLaptop && <AuthorDetails post={post} />}
    </Wrapper>
  );
};

const Image = styled.img`
  width: 100%;
  height: 100%;
  margin: 0 auto;
  object-fit: contain;
  cursor: pointer;
`;

const Header = tw.div`flex justify-between items-center w-max gap-sm mt-sm`;

const Author = tw.img`w-12 h-12 rounded-full cursor-pointer`;
const AuthorMeta = tw.div``;
const AuthorName = tw.h4`text-darker-gray pr-1 pt-1 rounded-md hover:bg-lighter-gray cursor-pointer`;
const CreatedAt = tw.p`text-darker-gray`;
const UpdatedAt = tw.p`text-darker-gray`;

const Title = tw.h1`my-sm`;

const PostBody = tw.div`mt-md pb-md border-b border-light-gray border-solid`;

const CommentsContainer = styled.div`
  > *:not(:first-child) {
    ${tw`mt-sm`}
  }
  ${tw`mt-md`}
`;

const Content = tw.div`px-lg my-lg mob:(px-sm)`;

const Wrapper = tw.div`w-full h-full rounded-md overflow-hidden bg-white shadow`;

export default Post;
jaywcjlove commented 1 year ago

@am0029 Do you want to get the converted HTML of md?

jaywcjlove commented 1 year ago

@am0029

https://github.com/jaywcjlove/markdown-to-html/blob/1ea64520e4d9b2636b67c7fe3102a1e8264e3377/packages/markdown-to-html/src/index.ts#L42-L113

am0029 commented 1 year ago

after 2 hours digging into this typescript code and converting it to react code . I could not figure out where should i put this code ? in cllient side right ? or server side . my application is not typescript sadly . yes i think you right i want markdown converted to html . I did use their convert to html cdn in my index.html but . nothing happened same text from markdown editor

can you say what can i do ? should i pit this code in client side of project ? in files that contain the markdown editor right ? where markdown editor value={body} and onChange={setBody} in that i file i mean i convert this type script code with online websites and then put the code beside the markdown editor . but notthing happened . it just post text into website instead of embeeded video

can u explain just a little very little about this code and how can i use this code to convert text to html ?

is there any method like this ? easyier method . or can u explain a little more how can i make editor understand the html code

 <MDEditor
                  value={Convert2html(body)}
                  style={{ padding: 15 }}
                  linkTarget="_blank"
                  onChange={setBody}
                  height={400}

                  rehypePlugins={[[rehypeVideo]]}

                  textareaProps={{
                    placeholder: "اینجا تایپ کنید",
                  }}

                />
jaywcjlove commented 1 year ago

If you include MDEditor, you can use MDEditor.Markdown to preview your markdown code. @am0029

am0029 commented 1 year ago

but this is not working . i can not type in editor at all if i add .Markdown to it . and this is releated to my problem in html ? can not understand

<MDEditor.Markdown
                  value={body}
                  style={{ padding: 15 }}
                  linkTarget="_blank"
                  onChange={setBody}
                  height={400}

                  rehypePlugins={[[rehypeVideo]]}
                  source={body}

                  textareaProps={{
                    placeholder: "اینجا تایپ کنید",
                  }}
/>
jaywcjlove commented 1 year ago

@am0029 https://codesandbox.io/embed/markdown-editor-for-react-https-github-com-uiwjs-react-md-editor-issues-471-v91bp1?fontsize=14&hidenavigation=1&theme=dark

image

am0029 commented 1 year ago

@jaywcjlove it worked . thanks man u saved me no money no life but when some one is helping u without money . life become beautifull

my last question man

how can i change the code block background color ? for now code block background color is very very light gray

i want make it black like dev.to

what is solution for this ? what css code need to do this ?

change the background color of code block after posting into website thanks man

am0029 commented 1 year ago

@jaywcjlove it worked . thanks man u saved me no money no life but when some one is helping u without money . life become beautifull

my last question man

how can i change the code block background color ? for now code block background color is very very light gray

i want make it black like dev.to

what is solution for this ? what css code need to do this ?

change the background color of code block after posting into website thanks man

jaywcjlove commented 1 year ago

@am0029

image
JoeGaffney commented 1 year ago

Hey wondering if it's possible to load a blob:http video?

jaywcjlove commented 1 year ago

@JoeGaffney There are many examples here, you can refer to.