Add CloudCannon to Hugolify

Hi folks,

I’m Sébastien founder of Hugolify.

Hugolify is a Hugo framework that integrates several Headless, initially Netlify CMS then Decap CMS and Sveltia CMS. Recently I added compatibility with Pages CMS. Now I’m trying to add CloudCannon.

Hugolify is supposed to build the config file (via Hugolify Admin) for the CMS based on the requirements and settings. It has a library of collections, fields and blocks to simplify this CMS configuration.

I am currently working on the cloudcannon branch of:

My builder allowed me to create this file: see cloudcannon.config.yml in Hugolify-template (sorry I can’t add more links in this topic).

Currently I’m stuck on the array and object part with this error message even though I’ve added _inputs and subtype to options.

I’m pretty excited about adding CloudCannon to Hugolify so I hope I’ve been clear about my issue and motived CloudCannon experts :slight_smile:

This is just the beginning and I know there is still a long way to go to make Hugolify fully compatible with CloudCannon.

Cheers,

Sébastien

4 Likes

Hi Sébastien,

Welcome to the community :slight_smile: Sounds very interesting! We’re excited to see how it goes.

We’ve taken a look at your config for you (https://github.com/Hugolify/hugolify-template/blob/cloudcannon/cloudcannon.config.yml) and made some changes.

The changes:

  • add the correct structure config
  • reduce the duplication
  • remove any invalid keys

Here’s the result - just replace your existing config with this:

paths:
  static: static
  uploads: static/images/uploads

_snippets_imports:
  hugo: true

_inputs:
  date:
    type: datetime
    instance_value: NOW
    options:
      required: true
  description:
    type: text
    comment: Displayed in tabs, search results, and in SMS/Messages/Social networks preview
  draft:
    type: switch
    # default: true # TODO: move this default value to schema
  title:
    type: text
    comment: Displayed in tabs, search results, and in SMS/Messages/Social networks preview
    label: Page title
    options:
      required: true
  image:
    type: object
    options:
      structures: _structures.images
  images:
    type: array
    options:
      structures: _structures.images

_structures:
  images:
    values:
      - label: Image
        value:
          alt:
          credit:
          src:
        _inputs:
          alt:
            type: text
            comment: For an image that conveys information (leave blank if decorative image)
            label: Text alternative
          credit:
            type: markdown
            options:
              link: true
          src:
            type: image
            label: Image
            comment: 'Resize and compress image before sending: https://bulkresizephotos.com/fr?quality=90&type=width&width=1600'
            options:
              max_file_size: 7000
  offers:
    values:
      - label: Offer
        value:
          discount:
          hide_price: false
          price:
          text:
        _inputs:
          discount:
            type: text
            comment: 'Amount of the reduction, e.g: 30%'
            options:
              pattern: '^\d+%*$'
          hide_price:
            type: switch
          price:
            type: number
            comment: 'e.g.: 300000 (for 300 000 €)'

collections_config:
  pages:
    path: content
    create:
      path: '[relative_base_path]/{title|slugify}/_index.md'
    disable_add_folder: true
    icon: description
    schemas:
      default:
        path: archetypes/pages.md
  products:
    path: content/products
    create:
      path: '[relative_base_path]/{year}/{slug}.md'
    disable_add_folder: true
    schemas:
      default:
        path: archetypes/products.md
    _inputs:
      id:
        type: disabled
        instance_value: UUID
      isIndex:
        type: checkbox
        hidden: true
        # default: false # TODO: move this default value to schema
      offer:
        type: object
        options:
          structures: _structures.offers
      slug:
        type: text
        comment: 'Leave empty to automate with the title. **Be careful to SEO impact.**'
        options:
          pattern: '^[a-z0-9-]*$'
          pattern_message: Contain only lowercase letters, numbers, and hyphens, with no spaces, accents, or special characters

Rather than go through every change in here, let me know if there are any parts of this config file that you’re wondering about.

I’m also available to book for a video call if that’s easier for you.

Hope that helps! Keep us up to date on progress, or if you run into any blockers.

Best wishes,
Tom

1 Like

Hi @Tom_Richardson,

Thank you for your reply and clarifications.

Remove any invalid keys

I’m currently revising my builder so that it doesn’t include unnecessary arguments; it’s taking a while, but I’ll be finished soon.

Reduce the duplication

Since it’s a builder, duplication isn’t a problem for me, but could it be a performance issue for CloudCannon?

Add the correct structure config

The important question for me is: It is possible to use _inputs in array and object rather than structures?

Here’s what my builder is producing now:

Best wishes,
Sébastien

1 Like

Hey Sébastien,

The important question for me is: It is possible to use _inputs in array and object rather than structures?

You can configure the keys that are present inside of an object or array. But the syntax where you have an _inputs key inside of another inputs options is invalid. For example, this:

      image:
        name: Images
        options:
          _inputs:
            alt:
              comment: For an image that conveys information (leave blank if decorative image)
              name: Text alternative
              options:
                required: false
              type: text
          required: false
          subtype: object

Should instead become this:

      image:
        type: object
        name: Images
        options:
          subtype: object
      image.alt:
        type: text
        comment: For an image that conveys information (leave blank if decorative image)
        name: Text alternative
        options:
          required: false

The key difference being the use of dot syntax to configure an alt input inside of the image input. Just plain alt would work as well, but that wouldn’t be scoped to just alt inputs inside of image inputs — instead it would target any input on your site with the key of alt.

Hope that makes sense and answers your question! Let us know if not, or if you have any other questions.

Best wishes,
Tom

1 Like

Hi @Tom_Richardson,

I hope you had a good weekend.

If I follow the example you’re showing me for the fields of an array, I can do this:

# Config
collections_config_override: false
paths:
  static: static
  uploads: static/images/uploads

# Snippets
_snippets_imports:
  hugo: true

# Collections
collections_config:
  products:
    _inputs:
      blocks:
        options:
          structures: _structures.blocks
        type: array
      date:
        instance_value: NOW
        name: Date
        options:
          required: true
        type: datetime
      title:
        comment: Displayed in tabs, search results, and in SMS/Messages/Social networks
          preview
        name: Page title
        options:
          required: true
        type: text
    comment: All products
    create:
      path: '[relative_base_path]/{year}/{slug}'
    disable_add: false
    disable_add_folder: true
    i18n: true
    name: Products
    path: content/products
    schemas:
      default:
        path: archetypes/products.md
    singular_name: Product


# Structures
_structures:
  blocks:
    style: modal
    values:
    - _inputs:
        background:
          name: With a background?
          options:
            required: false
          type: switch
        heading:
          name: Heading
          options:
            required: false
            subtype: object
          type: object
        heading.surtitle:
          name: Surtitle
          options:
            required: false
          type: text
        heading.text:
          name: Text
          options:
            allow_resize: false
            initial_height: 100
            required: false
          type: markdown
        heading.title:
          name: Title
          options:
            required: false
          type: text
      label: Title
      preview:
        icon: format_h2
        text:
        - key: title
        - Title
      value:
        background: 
        heading: 

However, I still get an error in the head array within the structures.

It’s important for me to define the fields in the arrays because they are often overridden, so it’s simpler to manage on the builder side.

Am I missing something?

Thanks,

Sébastien

2 Likes

Hi Sébastien,

Same to you!

Looks almost there. The issue is that you’re trying to use the config under _inputs to create new keys, when the _inputs config is just used to configure keys. In other words, adding an entry for heading.text in your _inputs config will target a key of text that is nested under a heading key, and allow you to configure how that key will look and behave in CloudCannon. It won’t create the key under heading though.

To define which keys would be added to the heading object input when an editor adds something, you can use another structure like you’ve used for the blocks array. This would tell CloudCannon what the object should look like that gets added to heading. Then on that structure definition you can define the input behaviour for title, surtitle, and text.

I’ve modified your latest config so that there is a valid structure to add to the heading key. Also, the collections_config_override key is deprecated now, and the i18n key doesn’t do anything in CloudCannon.

# Config
collections_config_override: false # Deprecated key here

paths:
  static: static
  uploads: static/images/uploads

# Snippets
_snippets_imports:
  hugo: true

# Collections
collections_config:
  products:
    _inputs:
      blocks:
        options:
          structures: _structures.blocks
        type: array
      date:
        instance_value: NOW
        name: Date
        options:
          required: true
        type: datetime
      title:
        comment: Displayed in tabs, search results, and in SMS/Messages/Social networks
          preview
        name: Page title
        options:
          required: true
        type: text
    comment: All products
    create:
      path: '[relative_base_path]/{year}/{slug}'
    disable_add: false
    disable_add_folder: true
    i18n: true # This key doesn't exist in CloudCannon
    name: Products
    path: content/products
    schemas:
      default:
        path: archetypes/products.md

# Structures
_structures:
  blocks:
    style: modal
    values:
    - _inputs:
        background:
          name: With a background?
          options:
            required: false
          type: switch
        heading:
          name: Heading
          options:
            required: false
            structures: _structures.block_heading
          type: object
      label: Title
      preview:
        icon: format_h2
        text:
        - key: title
        - Title
      value:
        background: 
        heading:
  block_heading:
    values:
      - value:
          title:
          surtitle:
          text:
        _inputs:
          surtitle:
            name: Surtitle
            options:
              required: false
            type: text
          text:
            name: Text
            options:
              allow_resize: false
              initial_height: 100
              required: false
            type: markdown
          title:
            name: Title
            options:
              required: false
            type: text

Hope that makes sense - let me know if not!

Cheers,

Tom

1 Like