Skip to content

Instantly share code, notes, and snippets.

@Sebobo
Created May 8, 2020 07:00
Show Gist options
  • Save Sebobo/dd3c83794644c355e9c9c32c34944c7d to your computer and use it in GitHub Desktop.
Save Sebobo/dd3c83794644c355e9c9c32c34944c7d to your computer and use it in GitHub Desktop.
Nested schedule element without additional Content Collections for Neos CMS
# This is a variant of th enormal ContentComponent that already includes
# a prop which loads it's children as ContentCollectionRenderer and has the necessary caching configuration
# to make everything work like with the standard ContentCollection.
#
# You can inherit from this prototype instead of ContentComponent for the Schedule and Day types above
# and remove the `items` prop from them.
prototype(Meetup.Example:ContentCollectionComponent) < prototype(Neos.Neos:ContentComponent) {
items = Neos.Neos:ContentCollectionRenderer
@cache {
mode = 'cached'
entryIdentifier {
collection = ${node}
}
entryTags {
1 = ${Neos.Caching.descendantOfTag(node)}
2 = ${Neos.Caching.nodeTag(node)}
}
maximumLifetime = ${q(node).context({'invisibleContentShown': true}).children().cacheLifetime()}
}
}
# This is a simple helper to not have to write the data attribute manally into the renderer
prototype(Meetup.Example:Helper.CollectionTag) < prototype(Neos.Fusion:Tag) {
attributes {
data-__neos-insertion-anchor = true
data-__neos-insertion-anchor.@if.inBackend = ${node ? node.context.inBackend : false}
}
}
Meetup.Example:Content.Schedule.Day:
superTypes:
Neos.Neos:Content: true
Neos.Neos:ContentCollection: true
constraints:
nodeTypes:
'*': false
Neos.Neos:Content: false
Meetup.Example:Content.Schedule.Item: true
ui:
label: Schedule Day
icon: calendar
properties:
title:
type: string
ui:
inlineEditable: true
inline:
editorOptions:
placeholder: Enter title...
Meetup.Example:Content.Schedule.Item:
superTypes:
Neos.Neos:Content: true
ui:
label: Schedule item
icon: clock
inspector:
groups:
schedule:
label: Schedule
icon: clock
properties:
title:
type: string
ui:
inlineEditable: true
inline:
editorOptions:
placeholder: Enter title...
description:
type: string
ui:
inlineEditable: true
inline:
editorOptions:
placeholder: Enter description...
start:
type: DateTime
ui:
label: Start
reloadIfChanged: true
inspector:
group: schedule
editorOptions:
format: 'H:i'
end:
type: DateTime
ui:
label: End
reloadIfChanged: true
inspector:
group: schedule
editorOptions:
format: 'H:i'
Meetup.Example:Content.Schedule:
superTypes:
Neos.Neos:Content: true
Neos.Neos:ContentCollection: true
constraints:
nodeTypes:
'*': false
Neos.Neos:Content: false
Meetup.Example:Content.Schedule.Day: true
ui:
label: Schedule
group: plugins
icon: clock
inlineEditable: true
# This is just for making the styles of the example work by including tailwindcss
# You should not use this in production
prototype(Neos.Neos:Page) {
head {
stylesheets {
tailwind = Neos.Fusion:Tag {
tagName = 'link'
attributes {
rel = 'stylesheet'
href = 'https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css'
}
}
}
}
}
prototype(Meetup.Example:Content.Schedule.Day) < prototype(Neos.Neos:ContentComponent) {
items = Neos.Neos:ContentCollectionRenderer
title = Neos.Neos:Editable {
property = 'title'
}
renderer = afx`
<div>
<span class="text-gray-900 relative inline-block uppercase font-medium tracking-widest">
{props.title}
</span>
<Meetup.Example:Helper.CollectionTag>
{props.items}
</Meetup.Example:Helper.CollectionTag>
</div>
`
}
prototype(Meetup.Example:Content.Schedule) < prototype(Neos.Neos:ContentComponent) {
days = Neos.Neos:ContentCollectionRenderer
renderer = afx`
<div class="flex justify-center p-24 bg-gray-100">
<Meetup.Example:Helper.CollectionTag
attributes.class="bg-white rounded-lg w-2/3 lg:w-1/2 xl:w-1/3 p-4 shadow"
>
{props.days}
</Meetup.Example:Helper.CollectionTag>
</div>
`
}
prototype(Meetup.Example:Content.Schedule.Item) < prototype(Neos.Neos:ContentComponent) {
title = Neos.Neos:Editable {
property = 'title'
}
description = Neos.Neos:Editable {
property = 'description'
}
start = ${q(node).property('start')}
end = ${q(node).property('end')}
renderer = afx`
<div class="flex mb-4">
<div class="w-2/12">
<span class="text-sm text-gray-600 block">{Date.format(props.start, 'H:i')}</span>
<span class="text-sm text-gray-600 block">{Date.format(props.end, 'H:i')}</span>
</div>
<div class="w-1/12">
<span class="bg-blue-400 h-2 w-2 rounded-full block mt-2"></span>
</div>
<div class="w-9/12">
<span class="text-sm font-semibold block">{props.title}</span>
<span class="text-sm">{props.description}</span>
</div>
</div>
`
}
@Sebobo
Copy link
Author

Sebobo commented Aug 5, 2020

It shouldn't work without. Except if your Fusion is different or you didn't test all cases. Which means: Adding a new node via the structure tree and checking that is in the correct position.

@etlam
Copy link

etlam commented Aug 6, 2020

You are right, our configuration is slightly different:
When a user inserts our wrapping element (the Schedule) we already insert one child node.
After this all following nodes get created in the right place, but you can not delete the programtically inserted childNode.

When you do not insert a childNode on creation the new nodes are created in the wrong position.
I am going to add the data-__neos-insertion-anchor="true" to our NodeType.

Thank you 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment