The CWA is in heavy development

The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
Basic Usage

Create a component

In 5 minutes you will have your own component defined in your API, front-end and with in-line content management.

Let's say we want a user to be able to add a title to their website as a UI component that you have styled.

Make sure you have setup your JWT authentication, and then you can login at https://localhost/login to use the management system
You should familiarise yourself with creating a resource using API Platform as we will skip over some of this.

Back-End (API)

First, you should define your back-end and what data in your UI component you want a website administrator to be able to edit. For this component, you know you will want the user to edit the title text.

Create your class extending AbstractComponent:

Define your class
<?php

namespace App\Entity;

use Silverback\ApiComponentsBundle\Entity\Core\AbstractComponent;

class Title extends AbstractComponent
{
    public ?string $title = null;
}

Now we will add some PHP annotation to mark this as an API resource and map it as a database entity. We have also defined this resource to publish to Mercure for real-time updates.

Add PHP annotations for API Platform and Doctrine
<?php
...
use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;

#[Orm\Entity]
#[ApiResource(mercure: true)]
class Title extends AbstractComponent
{
    #[Orm\Column(type: 'text', nullable: true)]
    public ?string $title = null;
}

Then, we can add the annotation provided by the ApiComponentsBundle Symfony bundle which provides extensions for more advanced functionality.

Add CWA annotations
<?php
...
use Silverback\ApiComponentsBundle\Annotation as Silverback;
use Silverback\ApiComponentsBundle\Entity\Utility\PublishableTrait;

#[Silverback\Publishable]
#[Orm\Entity]
#[ApiResource(mercure: true)]
class Title extends AbstractComponent
{
    use PublishableTrait;

    #[Assert\NotBlank(groups: ['Title:published'])]
    #[Orm\Column(type: 'text', nullable: true)]
    public ?string $title = null;
}

Finally, we can easily add validation to the title so that a published version cannot have a blank title. Your final class should look like this.

api/src/Entity/Title.php
<?php

namespace App\Entity;

use Silverback\ApiComponentsBundle\Entity\Core\AbstractComponent;
use ApiPlatform\Metadata\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Silverback\ApiComponentsBundle\Annotation as Silverback;
use Silverback\ApiComponentsBundle\Entity\Utility\PublishableTrait;
use Symfony\Component\Validator\Constraints as Assert;

#[Silverback\Publishable]
#[Orm\Entity]
#[ApiResource(mercure: true)]
class Title extends AbstractComponent
{
    use PublishableTrait;

    #[Orm\Column(type: 'text', nullable: true)]
    #[Assert\NotBlank(groups: ['Title:published'])]
    public ?string $title = null;
}
Remember to update your doctrine migrations and schema in your PHP container by running bin/console doctrine:migrations:diff and bin/console doctrine:migrations:migrate once you have checked the migration meets your needs.

Easy right? Now let's make the front-end.

Front-End

If you are familiar with creating Vue components, the following code examples will look very straight forward.

Convention is better than configuration: so we discover which CWA components are available through the directory structure. Additional configuration can be provided in your nuxt.config.ts file

Component

With our useCwaResource composable it is very easy to create your UI component. The composable provides many useful utilities so you can access your resource data, define the required properties and expose the required data for our internal management system.

app/cwa/components/Title/Title.vue
<template>
  <h1 class="text-primary text-4xl font-extrabold">
    {{ resource?.data?.title || 'No Title' }}
  </h1>
</template>

<script setup lang="ts">
  import { toRef } from 'vue'
  import { useCwaResource } from '#imports'
  import type { IriProp } from "#cwa/runtime/composables/cwa-resource";

  const props = defineProps<IriProp>()

  const { getResource, exposeMeta } = useCwaResource(toRef(props, 'iri'))

  const resource = getResource()

  defineExpose(exposeMeta)
</script>

Admin

Within the Title directory, you can create an admin folder to create new tabs for the component manager toolbar.

Here we can use 2 more useful composables. useCwaResourceManagerTab allows you to expose information, name your tab, set the order etc.

useCwaResourceModel takes an argument for the component identifier, and another for the field to update in the API.

We also have some commonly used UI components to use within the component manager toolbar.

Here is a complete example for managing your new Title component.

app/cwa/components/Title/admin/Title.vue
<template>
  <CwaUiFormLabelWrapper label="Title">
    <CwaUiFormInput v-model="titleModel.model.value" />
  </CwaUiFormLabelWrapper>
</template>

<script setup lang="ts">
  import { useCwaResourceManagerTab, useCwaResourceModel } from '#imports'

  const { exposeMeta, iri } = useCwaResourceManagerTab({ name: 'Title' })

  const titleModel = useCwaResourceModel<string>(iri, 'title')

  defineExpose(exposeMeta)
</script>

Congratulations!

That's it! 🚀

If you go to your website, you can how add a new Title component, see it become a draft as you edit it and then publish when ready. If you have another incognito window open with on the page, when you publish your new live version, you'll see a notification appear to update your view.