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

Basic setup returns error: "Failed to locate artboard element." #20

Open
Ravim-addweb opened this issue Apr 2, 2024 · 2 comments
Open

Comments

@Ravim-addweb
Copy link

Hello @dulnan @dasjo and @jonock !

I am trying the first instance of blokk.li with my fresh nuxt.js local setup and I am getting exceptions whenever I tap on the button to "Edit Blocks". Basically I've not invented any new functionalities, just trying to follow the doc so far.

Please find the versions and environment information below which may help you to diagnose the problem. Any help is much appreciated, the package looks really promising.

I am using: 18.14.2 node version on my Ubuntu 22.04 Chrome and Brave browsers.

Package.json:

{
  "name": "nuxt-app",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  },
  "dependencies": {
    "blokkli-beta": "^0.0.1-beta.0",
    "nuxt": "^3.11.1",
    "vue": "^3.4.21",
    "vue-router": "^4.3.0"
  }
}

nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['blokkli-beta'],

  blokkli: {
    // Only required configuration.
    // Should match the entity type of your blocks.
    itemEntityType: 'block',
  },
})

app/blokkli.editAdapter.ts:

import { defineBlokkliEditAdapter } from '#blokkli/adapter'

type YourStateType = {
  page: {
    title: 'My page'
  }
  editState: {
    currentMutationIndex: number
    mutations: any[]
    mutatedFields: any[]
    violations: any[]
    // etc.
  }
}

const bundles: BlockBundleDefinition[] = [
    {
      id: 'card',
      label: 'Card',
      description:
        'A block that renders a card with a title, text and a link.',
      allowReusable: true,
      isTranslatable: true,
    },
    {
      id: 'horizontal_rule',
      label: 'Horizontal Rule',
      description:
        'A block that renders a simple horizontal rule to separate content.',
      allowReusable: false,
      isTranslatable: false,
    },
    // etc.
  ]

export default defineBlokkliEditAdapter<YourStateType>((ctx) => {
    const mapState = (yourState: YourStateType): MappedState => {
        return {
          currentIndex: yourState.editState.currentMutationIndex,
          mutations: yourState.editState.mutations.map(mapMutation),
          currentUserIsOwner: yourState.page.owner.id === user.value.id,
          ownerName: yourState.page.owner.name,
          mutatedState: {
            fields: yourState.editState.mutatedFields.map(mapMutatedFields),
          },
          // etc.
        }
    }

  return {
    loadState: async (): YourStateType => {
      const response = await $fetch(
        `/backend-api/edit/${ctx.value.entityUuid}/get-state`,
      )
      return response.data
    },
    mapState,
    getAllBundles: () => {
        return Promise.resolve(bundles)
    },
    getFieldConfig: () => {
        const fieldConfig: FieldConfig[] = [
          {
            // Same name as on <BlokkliField>.
            name: 'field_blocks',
  
            // Same type and bundle of the <BlokkliProvider> the field
            // belongs to.
            entityType: 'content',
            entityBundle: 'blog_post',
  
            // The label displayed in the editor.
            label: 'Blocks',
  
            // The maximum number of blocks in this field. -1 means unlimited.
            cardinality: -1,
  
            // Whether the current user is allowed to edit the field.
            canEdit: true,
  
            // The block bundles that are allowed in this field.
            allowedBundles: ['title', 'rich_text', 'link', 'horizontal_rule'],
          },
        ]
        return Promise.resolve(fieldConfig)
    },
    addNewBlock: (e) => {
        return $fetch(`/api/edit/${ctx.value.entityUuid}/add-new-block`, {
          method: 'post',
          body: {
            // The block bundle to add.
            bundle: e.type,
  
            // The parent entity type where the block is being added.
            // Could be the entity type of the <BlokkliProvider> or in case
            // of nested blocks, the entity type of the block.
            entityType: e.host.type,
            entityUuid: e.host.uuid,
  
            // The field name where the block is added.
            fieldName: e.host.fieldName,
  
            // The UUID of the block that should be before the new one.
            preceedingUuid: e.afterUuid,
          },
        })
    },
    moveBlock: (e) => {
        return $fetch(`/backend-api/edit/${ctx.value.entityUuid}/move-block`, {
          method: 'post',
          body: {
            // The block being moved.
            uuid: e.item.uuid,
  
            // The parent entity type where the block is being added.
            // Could be the entity type of the <BlokkliProvider> or in case of nested blocks, the entity type of the block.
            entityType: e.host.type,
            entityUuid: e.host.uuid,
  
            // The field name where the block is added.
            fieldName: e.host.fieldName,
  
            // The UUID of the block that should be before the new one.
            // If undefined, the block should be moved to index 0 of the field list.
            preceedingUuid: e.afterUuid,
          },
        })
    },
    moveMultipleBlocks: (e) => {
        return $fetch(
          `/backend-api/edit/${ctx.value.entityUuid}/move-multiple-blocks`,
          {
            method: 'post',
            body: {
              // The UUIDs of the blocks being moved.
              uuids: e.uuids,
  
              // The parent entity type where the block is being added.
              // Could be the entity type of the <BlokkliProvider> or in case of nested blocks, the entity type of the block.
              entityType: e.host.type,
              entityUuid: e.host.uuid,
  
              // The field name where the block is added.
              fieldName: e.host.fieldName,
  
              // The UUID of the block that should be before the new one.
              // If undefined, the block should be moved to index 0 of the field list.
              preceedingUuid: e.afterUuid,
            },
          },
        )
    },
  }
})

app.vue:

<template>
  <BlokkliProvider
    entity-type="content"
    entity-bundle="blog_post"
    entity-uuid="9485812c-0ecd-4699-85b2-3a031d47a0a1"
    can-edit
  >
    <BlokkliField :list="blocks" name="blocks" />
  </BlokkliProvider>
</template>

<script lang="ts" setup>
const blocks = [
  {
    uuid: '96f7fbda-04d9-4662-9a6c-6aa3bcf964f2',
    bundle: 'title',
    props: {
      title: 'Hello world',
    },
  },
  {
    uuid: '9485812c-0ecd-4699-85b2-3a031d47a0a1',
    bundle: 'rich_text',
    props: {
      text: '<p>Lorem ipsum dolor sit amet</p>',
    },
  },
  {
    uuid: '5407ef47-dfbc-456b-9900-8e2577185380',
    bundle: 'horizontal_rule',
  },
  {
    uuid: 'f91e046b-3bcc-48dd-bbd5-8a21115436b7',
    bundle: 'link',
    options: {
      linkType: 'button',
    },
    props: {
      label: 'Learn more',
      href: '/learn-more',
    },
  },
]
</script>

components/Blocks/Title.vue:

<template>
  <h2>{{ title }}</h2>
</template>

<script lang="ts" setup>
defineBlokkli({
  bundle: 'title',
})

defineProps<{
  title: string
}>()
</script>

Here's the output snapshot:

image

The error says:

uiProvider.mjs?v=e08a98ab:31 Uncaught (in promise) Error: Failed to locate artboard element.
    at artboardElement (uiProvider.mjs?v=e08a98ab:31:13)

Please let me know what I am missing, really looking forward to take this further. Thanks!

@dulnan
Copy link
Collaborator

dulnan commented Apr 2, 2024

Ah, this is something that's completely missing from the docs I just realised. Sorry for that!

What you need is to have a single HTML element somewhere in your app with the class bk-main-canvas. I always put it in my root element in app.vue:

<template>
  <div class="bk-main-canvas">
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
  </div>
</template>

Bascially what this does is tell blökkli which element should be used for the "artboard". Inside the editor, this element will be made position: fixed, it receives a drop shadow and is made zoomable/draggable. In most cases the root element of the app is where this makes most sense, but it could also be in the layout or in your page component.

@Ravim-addweb
Copy link
Author

Thanks @dulnan that makes sense, I have checked the playground of the editor and that just worked.

Side question: I have noticed in the live demo that, I can use Text and YouTube videos on the clipboard. But when I try to drop the image pasted on the clipboard into the editor, it doesn't work. YouTube and Text are being dropped on the editor but not the image. Is that something already on the cards?

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

2 participants