Darginec05 / Yoopta-Editor

Build Notion-like, Craft-like, Coda-like, Medium-like editors with Yoopta
https://yoopta.dev/
MIT License
1.36k stars 103 forks source link

Help Needed: Custom Block Plugin #357

Open Quietscher opened 2 weeks ago

Quietscher commented 2 weeks ago

What's the example?

Hello! I want to create a custom block component, and I've looked at the carousel example. It should have multiple text inputs and subcomponents. I can't get it to work that the use can input text (that is saved and so on)...

You can think of it as Card CardHeader CardContent

(where one can enter text as header and as content)

I would be very glad for some explanation, thanks!

Code of Conduct

Darginec05 commented 2 weeks ago

Hi @Quietscher 👋 Do you have UI or layout for this plugin/block? I want to take a look to understand the structure

Quietscher commented 2 weeks ago

Hi @Quietscher 👋 Do you have UI or layout for this plugin/block? I want to take a look to understand the structure

Hey 👋

<Card {...attributes} key={blockId}>
                <CardHeader>
                    <CardTitle>Marker</CardTitle>
                    <CardDescription>Card Description</CardDescription>
                    <DateTimePicker />
                </CardHeader>
                <CardContent>
                    <div className="flex flex-row items-start justify-start">
                        <div className="ml-10 max-w-xs">
                            <Carousel
                                plugins={[
                                    Autoplay({
                                        delay: 3000,
                                    }),
                                ]}
                            >
                                <CarouselContent>
                                    {Array.from({ length: 5 }).map((_, index) => (
                                        <CarouselItem key={index}>
                                            <Card className="mb-2 mx-1">
                                                <CardContent className="flex aspect-square items-center justify-center p-6">
                                                    <span className="text-4xl font-semibold">
                                                        {index + 1}
                                                    </span>
                                                </CardContent>
                                            </Card>
                                        </CarouselItem>
                                    ))}
                                </CarouselContent>
                                <CarouselPrevious />
                                <CarouselNext />
                            </Carousel>
                        </div>
                    </div>
                </CardContent>
                <CardFooter>
                    <p>Card Footer</p>
                </CardFooter>
            </Card>
        sth like this
Quietscher commented 2 weeks ago
export const MarkerBlock = ({
    attributes,
    children,
    element,
    blockId,
}: PluginElementRenderProps) => {
    return (
        <>
            <Card {...attributes}>
                {...children}
            </Card>
        </>
    );
};

export const MarkerCardContent = ({ children }: PluginElementRenderProps) => {
    return <CardContent>{...children}</CardContent>;
};

export const MarkerHeader = ({ children }: PluginElementRenderProps) => {
    return <CardHeader>{...children}</CardHeader>;
};

export const MarkerDate = ({ element }: PluginElementRenderProps) => {
    let newDate = new Date(element.props.timestamp);
    const [date, setDate] = useState<Date | undefined>(newDate ?? undefined);
    return <DateTimePicker date={date} setDate={setDate} />;
};

export const MarkerDescription = ({ children }: PluginElementRenderProps) => {
    return <CardDescription>{...children}</CardDescription>;
};

export const MarkerTitle = ({ children }: PluginElementRenderProps) => {
    return <CardTitle>{...children}</CardTitle>;
};

export const MarkerBody = ({
    attributes,
    children,
    element,
    blockId,
}: PluginElementRenderProps) => {
    const imgSrc: string[] | undefined = element.props.imgSrcs;

    return (
        <div {...attributes}>
            {imgSrc && imgSrc.length > 0 && (
                <div className="flex flex-row items-start justify-start">
                    <div className="ml-10 max-w-xs">
                        <Carousel
                            plugins={[
                                Autoplay({
                                    delay: 3000,
                                }),
                            ]}
                        >
                            <CarouselContent>
                                {imgSrc.map((src: string, index: any) => (
                                    <CarouselItem key={index}>
                                        <Card className="mb-2 mx-1">
                                            <CardContent className="flex aspect-square items-center justify-center p-0 m-0">
                                                <Image src={src} alt={index} />
                                            </CardContent>
                                        </Card>
                                    </CarouselItem>
                                ))}
                            </CarouselContent>
                            <CarouselPrevious />
                            <CarouselNext />
                        </Carousel>
                    </div>
                </div>
            )}
            {...children}
        </div>
    );
};

export type MarkerBlockType = SlateElement<'marker-block'>;
export type MarkerCardContentType = SlateElement<'marker-content'>;
export type MarkerBodyType = SlateElement<'marker-body', MarkerBodyProps>;
export type MarkerHeaderType =  SlateElement<'marker-header'>;
export type MarkerDateType =  SlateElement<'marker-date', MarkerDateProps>;
export type MarkerDescriptionType =  SlateElement<'marker-description'>;
export type MarkerTitleType =  SlateElement<'marker-title'>;

const MarkerBlockPlugin = new YooptaPlugin({
    type: 'Block',
    elements: {
        'marker-block': {
            render: MarkerBlock,
            children: ['marker-header','marker-content'],
            asRoot: true,
            props: {
                timestamp: new Date().getMilliseconds(),
            },
        },
        'marker-content': {
            render: MarkerCardContent,
            children: ['marker-body']
        },
        'marker-header': {
            render: MarkerHeader,
            children: ['marker-date','marker-title', 'marker-description'],
        },
        'marker-date': {
            render: MarkerDate,
            props: {
                timestamp: new Date().getMilliseconds(),
            },
        },
        'marker-title': {
            render: MarkerTitle,
        },
        'marker-description': {
            render: MarkerDescription,
        },
        'marker-body': {
            render: MarkerBody,
            props: {
                imgSrcs: [],
            },
        },
    },

This is what i currently have

Quietscher commented 1 week ago

Hey @Darginec05 😊 Have you had a chance to look at it yet? Thanks -Quirin

Darginec05 commented 1 week ago

Hi @Quietscher 👋 I'm currently preparing release and writing docs I think I can help you in more detail only on the weekend

Darginec05 commented 6 days ago

@Quietscher I'm finally here :D Do you have any UI for your custom plugin? This will help me understand the structure better

Quietscher commented 6 days ago

Nice! Hmm i dont have any Screenshot... I try to make a custom Element with the following attributes:

That all in one custom block

So after creating the block, the user can set a title a content, pictures, a date and so on.

Id like to save the content that the user creates in the block separately in an object ill push to My backend.