Editable structure field previews for custom block

This would be one option. Or adding your own custom CSS. In the end, if you rebuild the drawer fieldset 1:1, it’d be easier to just use the preview: fields I linked to above. Couldn’t quite follow why the structure field would be an issue there or what your custom preview would do differently then for the structure field part.

It looks like you removed this though when started working with <k-text-input>. You can pass the placeholder to it in the same way as with the native input element. Have a look at the docs for k-text-input where you can find a full list of what props this component supports/accepts - so all you could pass to it (incl. the placeholder).

The colon was missing. Now the placeholder works perfectly!

:placeholder= "field('heading').placeholder"

Well, as mentioned before, you cannot edit structure fields without the drawer. That is why I build custom blocks. And now this block works well. I can edit the structure fields directly without the drawer but the design is still not like I want it to be. The toggle field has a different height and I try to figure out what the right height is and how to implement it. I will try this with a structure block now. The text block is a test.

panel.plugin("tillcremer/index-theme-blocks", {
    blocks: {
        textblock: {
            methods: {
                editHeading(value) {
                    this.update({
                        heading: value
                    });
                },
                editToggle(value) {
                    this.update({
                        toggle: value
                    });
                },
                editText(value) {
                    this.update({
                        text: value
                    });
                }
            },
            template: `
                <section class="k-block k-block-type-textblock">    
                    <k-grid variant="fields">    
                        <k-box theme="empty" style="--width: 3/4">         
                            <k-writer-input
                                name="writer"
                                :autofocus="true"
                                :placeholder= "field('heading').placeholder"
                                :value="content.heading"
                                @input="editHeading"
                                style="--width: 3/4"
                            />     
                        </k-box> 
                        <k-box theme="empty" style="--width: 1/4">
                            <k-toggle-input 
                                name="toggle" 
                                :value="content.toggle" 
                                @input="editToggle"
                                style="--width: 1/4"
                            />   
                        </k-box>
                        <k-box theme="empty" style="--width: 1/1">
                            <k-writer-input
                                name="writer"
                                :autofocus="true"
                                :placeholder="field('text').placeholder"
                                :value="content.text"
                                @input="editText"
                            />    
                        </k-box>                      
                    </k-grid>           
                </section>
            `
        }    
    }
});

In the screencast, @bastianallgeier says, there can be defined multiple blocks in the index.js. I try to setup the second block but it only appears rudimentary. When I call up the block editor in the panel, not even the correct name of the block is displayed. Did I miss a semicolon or something else? <k-code>{{ content }}</k-code> gives an empty black field with two brackets.

panel.plugin("tillcremer/kirby-index-theme-blocks", {
    blocks: {
        textblock: {
            methods: {
                editHeading(value) {
                    this.update({
                        heading: value
                    });
                },
                editToggle(value) {
                    this.update({
                        toggle: value
                    });
                },
                editText(value) {
                    this.update({
                        text: value
                    });
                }
            },
            template: `
                <section class="k-block k-block-type-textblock">    
                    <k-grid variant="fields">    
                        <k-box theme="empty" style="--width: 3/4">         
                            <k-writer-input
                                name="writer"
                                :autofocus="true"
                                :placeholder= "field('heading').placeholder"
                                :value="content.heading"
                                @input="editHeading"
                                style="--width: 3/4"
                            />     
                        </k-box> 
                        <k-box theme="empty" style="--width: 1/4">
                            <k-toggle-input 
                                name="toggle" 
                                :value="content.toggle" 
                                @input="editToggle"
                                style="--width: 1/4"
                            />   
                        </k-box>
                        <k-box theme="empty" style="--width: 1/1">
                            <k-writer-input
                                name="writer"
                                :autofocus="true"
                                :placeholder="field('text').placeholder"
                                :value="content.text"
                                @input="editText"
                            />    
                        </k-box>                      
                    </k-grid>           
                </section>
            `
        },
        tableblock: {
            methods: {
                editHeading(value) {
                    this.update({
                        heading: value
                    });
                },
                editToggle(value) {
                    this.update({
                        toggle: value
                    });
                },
                editTableField(value) {
                    this.update({
                        text: value
                    });
                }
            },
            template: `
                <section class="k-block k-block-type-tableblock">   
                     <k-grid variant="fields">    
                        <k-box theme="empty" style="--width: 3/4">         
                            <k-writer-input
                                name="writer"
                                :autofocus="true"
                                :placeholder= "field('heading').placeholder"
                                :value="content.heading"
                                @input="editHeading"
                                style="--width: 3/4"
                            />     
                        </k-box> 
                        <k-box theme="empty" style="--width: 1/4">
                            <k-toggle-input 
                                name="toggle" 
                                :value="content.toggle" 
                                @input="editToggle"
                                style="--width: 1/4"
                            />   
                        </k-box>                  
                    </k-grid>   
                    
                    <!--
                    <div class="k-table">
                        <table>
                            <thead>
                                <tr>
                                    <th class="k-table-index-column">#</th>
                                    <th>Name</th>
                                    <th>Email</th>
                                    <th>URL</th>
                                    <th>Date</th>
                                    <th class="k-table-options-column"></th>
                                </tr>
                            </thead>
                            <k-draggable
                                :handle="true"
                                :options="{
                                    fallbackClass: 'k-table-row-fallback',
                                    ghostClass: 'k-table-row-ghost'
                                }"
                                element="tbody"
                            >
                                <tr v-for="i in 2" :key="i">
                                    <td class="k-table-index-column" data-sortable="true">
                                        <span class="k-table-index">{{ i }}</span>
                                        <k-sort-handle />
                                    </td>
                                    <td>Kirby</td>
                                    <td>mail@getkirby.com</td>
                                    <td>https://getkirby.com</td>
                                    <td>2023-09-25</td>
                                    <td class="k-table-options-column">
                                        <k-options-dropdown :options="options" />
                                    </td>
                                </tr>
                            </k-draggable>
                        </table>
                    </div> 
                    -->
                </section>
            `
        }        
    }
});
<?php 

Kirby::plugin('tillcremer/kirby-index-theme-blocks', [
  'blueprints' => [
    'blocks/textblock' => __DIR__ . '/blueprints/blocks/textblock.yml'
  ],
  [
    'blocks/tableblock' => __DIR__ . '/blueprints/blocks/tableblock.yml'
    ]
  ]);
name: Table Block with Heading
type: tableblock
icon: table
fields:
  heading:
    label: Heading
    type: writer
    inline: true
    width: 3/4
    required: true
    placeholder: Heading
    nodes: false
    marks:
      - italic
      - underline
      - strike
      - sub
      - sup
      - clear
  toggle:
    label: false
    type: toggle                
    text: 
      - hide
      - show
    default: true  
    width: 1/4  
  table:
    label: Table
    type: structure
    fields:
      date:
        label: Year or Time Span
        type: text
        pattern: "[0-9]{4}|[0-9]{4}–[0-9]{4}"
        translate: false
        placeholder: "2020–2022"
        width: 1/4
      item:
        label: Story
        type: writer
        nodes: false
        marks:
          - italic
          - underline
          - strike
          - sub
          - sup
          - clear
        width: 3/4

I have to ask you to try to be a bit clearer with your support requests because it is really hard to reply to your messages and offer meaningful support as often what you write has little connection to the code you post or the screenshots you share.

E.g. I have no clue what you refer to with <k-code>{{ content }}</k-code> as that appears nowhere in the code you shared. And so the code you shared and your screenshot don’t seem to be related at all.

E.g. we’ll have a hard time figuring out why not both blocks are available to you without sharing your blueprint - how are you trying to use them in your blueprint?

So please when writing these, don’t rush it but take some time. Really explain step by step what you did, what your code is, what is happening/not happening as you expected etc.

No hard feelings, but without it we won’t be much of help.

This is used in the screencast to show all available content. I used this code to show if there is something wrong in my template: fault localization.

Okay, to keep it more simple: Is it possible to store multiple blocks in index.js or do I need a plugin for every custom block type? If possible, how do I have to separate each block in the script? With a comma or a semicolon? I could not find any example.

It is definitely possible and I don’t see any obvious problem with your code there. Syntax is

panel.plugin("my/pluginname", {
  blocks: {
    blockA:{
      // ...
    },
    blockB: {
      // ...
    }
  }
})

There was an error in the index.php. It should list all blocks like this:

<?php 

Kirby::plugin('tillcremer/kirby-index-theme-blocks', [
  'blueprints' => [
    'blocks/textblock' => __DIR__ . '/blueprints/blocks/textblock.yml',
    'blocks/tableblock' => __DIR__ . '/blueprints/blocks/tableblock.yml'
  ]
  ]);

I am almost there. My two custom blocks work well. Now I have a further question: How do I get the structure field content into my panel table? At the moment, I just display the heading, the toggle, and the available structure content. My code so far:

        tableblock: {
            methods: {
                editHeading(value) {
                    this.update({
                        heading: value
                    });
                },
                editToggle(value) {
                    this.update({
                        toggle: value
                    });
                }
            },
            template: `
                <section class="k-block k-block-type-tableblock">  
                    <k-grid variant="fields">    
                        <k-box theme="empty" style="--width: 3/4">         
                            <k-writer-input
                                name="writer"
                                :autofocus="true"
                                :placeholder= "field('heading').placeholder"
                                :value="content.heading"
                                @input="editHeading"
                                style="--width: 3/4"
                            />     
                        </k-box> 
                        <k-box theme="empty" style="--width: 1/4">
                            <k-toggle-input 
                                name="toggle" 
                                :value="content.toggle" 
                                @input="editToggle"
                                style="--width: 1/4"
                            />   
                        </k-box>            
                    </k-grid>   
                    <k-code>{{ content }}</kode>   
                </section>
            `
        }

I read about the Editable preview. The table should be sortable and the content in sync with the drawer. I would like to use the Index with sort handle here:

<div class="k-table">
	<table>
		<thead>
			<tr>
				<th class="k-table-index-column">#</th>
				<th>Name</th>
				<th>Email</th>
				<th>URL</th>
				<th>Date</th>
				<th class="k-table-options-column"></th>
			</tr>
		</thead>
		<k-draggable
			:handle="true"
			:options="{
				fallbackClass: 'k-table-row-fallback',
				ghostClass: 'k-table-row-ghost'
			}"
			element="tbody"
		>
			<tr v-for="i in 2" :key="i">
				<td class="k-table-index-column" data-sortable="true">
					<span class="k-table-index">{{ i }}</span>
					<k-sort-handle />
				</td>
				<td>Kirby</td>
				<td>mail@getkirby.com</td>
				<td>https://getkirby.com</td>
				<td>2023-09-25</td>
				<td class="k-table-options-column">
					<k-options-dropdown :options="options" />
				</td>
			</tr>
		</k-draggable>
	</table>
</div>

You are describing that you are literally rebuilding what preview: fields gives you out of the box. Have you tried it even?

Yes, I did. As mentioned above: block structure fields are only editable in the drawer! Or am I wrong? My experience is that structure fields work great as fields but when using them in a custom block you have to edit every field in the drawer. Please try it yourself.

With preview: fields the structure field is editable the same inside the block as outside of blocks. If you also want to get around the structure field drawer (not the block drawer), preview: fields would still make sense as you then at least don’t have to rebuild all the other fields. For the structure field itself you will need to implement custom field previews that also can update the content: kirby/panel/src/components/Forms/Previews at main · getkirby/kirby · GitHub

This is a quite advanced project where you’d need to familiarize yourself with how field previews are constructed and implemented. For that I would recommend you to get a lot more familiar with Vue in general and Panel components in particular. I don’t think similar things have been implemented by many others, so neither I nor others will probably be able to guide you there step by step but can only point you to that direction.

Apologies if I misunderstood you earlier. As I wrote, your comments and questions are not always easy to follow when they’re rather brief and jump around.

I would love to use the built-in components. Perhaps I have overlooked something? So, once again, I created a custom block in the folder site/blueprints/blocks/structure.yml. This is the code of the block:

name: Structure to Table
icon: table
preview: fields
wysiwyg: true
fields:
  emails:
    label: Emails
    type: structure
    fields:
      email:
        label: Email
        type: email
      name:
        label: name
        type: text

When I switch to the panel, add this kind of block and enter some content, it look like this:

When I click into a field to edit it, the drawer opens and I am able to edit it. It looks like this:

That is what I am talking about. You say the structure fields are directly editbale without the drawer. But how do I achieve this? Did I miss anything? I would really like to save myself the complicated part.

No, they aren’t editable inline. My understanding was that your problem is the block drawer (with all the fields of the block) and that you would want to skip that one. For that preview: fields works. But it still leaves you then with the structure drawer to edit a row of the structure field. That drawer remains - but this is not a speciality of blocks/a block preview, the structure field table is never editable inline also not as standalone field (exception: column for toggle fields, that’s the only one that supports inline editing so far).

To make a structure field table editable inline (no matter if in a standalone structure field or inside the preview: fields preview of your block) you would need to overwrite all relevant field previews, implement the handling of inputs and updates etc. I cannot advise you how to do it. Personally, I would stay away from it.

We would love to support inline editing for the structure field table at some point. But this will for sure take a few more releases until we can offer this in Kirby by default. Sorry :confused:

This is strange. I am reworking a Kirby 3 site. There, I realised several structure fields. When editing it looks like this:


Here, a window pops up within the structure field. Another kind of drawer which I am unable to recreate.

Yes structure field editing changed from Kirby 3 to 4.

Well, @Bogdan_Condorachi created a great plugin for table fields. He managed to realise such a thing. Probably, I will find a way to realise my idea of <section> blocks consisting of several fields including a table.