Atomic.Fusion & Sitegeist.Monocle - Neos Conference 2017

Atomic.Fusion & Sitegeist.Monocle - Neos Conference 2017

An presentation of sitegeists approach for component based fusion development that enabled the creation of living styleguide in Neos.

8682955fc87df72a1c9284b271e9f414?s=128

Sitegeist

March 31, 2017
Tweet

Transcript

  1. Atomic.Fusion + Sitegeist.Monocle Wilhelm Behncke & Martin Ficzel

  2. Full Stack Developer

 +sitegeist behncke@sitegeist.de twitter: @WilhelmBehncke
 slack: @wbehncke

 Neos

    Team-Member, Musician Wilhelm Behncke
  3. Backend Developer

 +sitegeist ficzel@sitegeist.de
 twitter/slack: @kopfaufholz

 Neos Team-Member,
 2 Kids,

    Climber Martin Ficzel
  4. Fluid Partials and Logic in Templates

  5. Evolution of an Image Partial <img src="http://dummyimage.com/400/200" alt="Alternate Text" title="Title

    Text" /> Part 1 - Frontend creates Image-Partial
  6. Evolution of an Image-Partial <f:image image="{image}" alt="{altText}" title="{node.property.title}" /> Part

    2 - Backend alters Partial to render image.
  7. Evolution of an Image Partial <f:if condition="{link}"> <f:then> <f:if condition="{neos.rendering.inBackend()}">

    <f:then> <f:render section="image" attributes="{_all}" /> </f:then> <f:else> <a href="{link}"> <f:render section="image" attributes="{_all}" /> </a> </f:else> </f:if> </f:then> <f:else> <f:render section="image" attributes="{_all}" /> </f:else> </f:if> <f:section name="image"> <f:image image="{image}" alt="{altText}" title="{node.property.title}" /> Part 3 - Backend adds optional link
  8. The challenges for bigger projects 1. Partials don't scale well

    2. Proper context boundaries are missing 3. That way Frontend to backend collaboration is a one way trip
  9. Collaboration

  10. Styleguides

  11. Living Styleguides

  12. We want a living-styleguide for Neos

  13. We want a living-styleguide for Neos What do we have

    to do to get it?
  14. Keep your filthy state off my views!

  15. None
  16. None
  17. None
  18. None
  19. None
  20. None
  21. None
  22. None
  23. None
  24. Components are everywhere React, Preact, Inferno... Angular, Ember, Vue.js... Web

    Components
  25. Components Solely determined by their attributes, (Side-effect free) Single purpose

    Encapsulate everything that is needed to re-use them
  26. Atomic.Fusion

  27. Atomic.Fusion - Component prototype(Vendor.Site:Component.Atom.Link) < prototype(PackageFactory.AtomicFusion:Component) { # component api

    text = '' uri = '' # component renderer renderer = Neos.Fusion:Tag { tagName = 'a' content = Neos.Fusion:Array { text = ${props.text} } attributes.src = ${props.uri}
 } }
  28. Atomic.Fusion - Composition prototype(Vendor.Site:Component.Organism.Header) < prototype(PackageFactory.AtomicFusion:Component) { renderer = Neos.Fusion:Array

    { funcNav = Vendor.Site:Component.Molecule.FuncNav mainNav = Vendor.Site:Component.Molecule.MainNav home = Vendor.Site:Component.Atom.Link { src = '/' } } }
  29. Atomic.Fusion Not to be confused with Atomic.Design Nuclear.Fusion Github: https://github.com/PackageFactory/atomic-fusion

    Packagist: composer require packagefactory/atomicfusion Used in production
  30. Sitegeist.Monocle

  31. Sitegeist.Monocle - Meta Data prototype(Vendor.Site:Component.Atom.Button) { @styleguide { # Meta

    Data path = 'atoms.basic' title = 'Button' description = 'generic Buttom Atom’ # Preview Data props { content = 'Lorem Ipsum'
 tagName = 'a' } } }
  32. Sitegeist.Monocle - Preview Data prototype(Vendor.Site:Component.Atom.Button) { @styleguide { # Meta

    Data path = 'atoms.basic' title = 'Button' description = 'generic Buttom Atom’ # Preview Data props { content = 'Lorem Ipsum'
 tagName = 'a' } } }
  33. None
  34. None
  35. None
  36. None
  37. Sitegeist.Monocle Github: https://github.com/sitegeist/Sitegeist.Monocle Packagist: composer require sitegeist/monocle It is used

    in Production Has no effect the on the neos-fusion runtime It does'nt need a database
  38. Atomic.Fusion - Mapping

  39. Atomic.Fusion - Mapping Content prototype(Vendor.Site:Content.Teaser) < prototype(Neos.Fusion:Renderer) { renderer =

    Vendor.Site:Component.Molecule.Teaser { layout = ${q(node).property('layout')} title.content = ${q(node).property('title')}
 description { content = ${q(node).property(‚description')}
 @process.makeEditable = Neos.Neos:ContentEditableWrapping
 @process.makeEditable.propertyName = 'description'
 } } @process.contentElementWrapping = Neos.Neos:ContentElementWrapping }
  40. Atomic.Fusion - Mapping Content prototype(Vendor.Site:Content.Teaser) < prototype(Neos.Fusion:Renderer) { renderer =

    Vendor.Site:Component.Molecule.Teaser { layout = ${q(node).property('layout')} title.content = ${q(node).property('title')}
 description { content = ${q(node).property(‚description')}
 @process.makeEditable = Neos.Neos:ContentEditableWrapping
 @process.makeEditable.propertyName = 'description'
 } } @process.contentElementWrapping = Neos.Neos:ContentElementWrapping }
  41. Atomic.Fusion - Mapping Content prototype(Vendor.Site:Content.Teaser) < prototype(Neos.Fusion:Renderer) { renderer =

    Vendor.Site:Component.Molecule.Teaser { layout = ${q(node).property('layout')} title.content = ${q(node).property('title')}
 description { content = ${q(node).property(‚description')}
 @process.makeEditable = Neos.Neos:ContentEditableWrapping
 @process.makeEditable.propertyName = 'description'
 } } @process.contentElementWrapping = Neos.Neos:ContentElementWrapping }
  42. Atomic.Fusion - Mapping Documents prototype(Vendor.Site:Document.Page) < prototype(Neos.Neos:Page) { body =

    Vendor.Site:Component.Template.Page { navigationItems = Neos.Fusion:RawCollection { collection = ${q(site).children('[instanceof Neos.Neos:Document]').get()} itemName = 'item' itemRenderer = Neos.Fusion:RawArray { title = ${q(item).property('titleOverride') ? q(item).property('titleOverride') : q(item).property( uri = Neos.Neos:NodeUri { node = ${item} } } } content = Neos.Neos:PrimaryContent { nodePath = 'main' } } }
  43. Atomic.Fusion - Mapping Documents prototype(Vendor.Site:Document.Page) < prototype(Neos.Neos:Page) { body =

    Vendor.Site:Component.Template.Page { navigationItems = Neos.Fusion:RawCollection { collection = ${q(site).children('[instanceof Neos.Neos:Document]').get()} itemName = 'item' itemRenderer = Neos.Fusion:RawArray { title = ${q(item).property('titleOverride') ? q(item).property('titleOverride') : q(item).property( uri = Neos.Neos:NodeUri { node = ${item} } } } content = Neos.Neos:PrimaryContent { nodePath = 'main' } } }
  44. Atomic.Fusion - Mapping Documents prototype(Vendor.Site:Document.Page) < prototype(Neos.Neos:Page) { body =

    Vendor.Site:Component.Template.Page { navigationItems = Neos.Fusion:RawCollection { collection = ${q(site).children('[instanceof Neos.Neos:Document]').get()} itemName = 'item' itemRenderer = Neos.Fusion:RawArray { title = ${q(item).property('titleOverride') ? q(item).property('titleOverride') : q(item).property( uri = Neos.Neos:NodeUri { node = ${item} } } } content = Neos.Neos:PrimaryContent { nodePath = 'main' } } }
  45. The challenges for bigger projects 1. Partials don't scale well

    Presentational components do! 2. Proper context boundaries are missing Components have boundaries In Fusion you can cross boundaries if needed 3. Frontend to backend collaboration works only in one direction Seperate presentational components enable independent. The Component API defines the interface between crafts.
  46. That's it

  47. Experimental content ahead

  48. Fusion Components - Today prototype(PackageFactory.AtomicFusion.AFX:Example) < prototype(PackageFactory.AtomicFusion:Component) { title =

    'title text' subtitle = 'subtitle line' imageUri = 'https://dummyimage.com/600x400/000/fff' renderer = Neos.Fusion:Tag { tagName = 'div' content = Neos.Fusion:Array { headline = Neos.Fusion:Tag { tagName = 'h1' content = Neos.Fusion:Array { 1 = ${props.title} } attributes.class = 'headline' } subheadline = Neos.Fusion:Tag { tagName = 'h2' content = Neos.Fusion:Array { 1 = ${props.subtitle} } attributes.subheadline = 'subheadline' @if.hasSubtitle = ${props.subtitle ? true : false} } image = PackageFactory.AtomicFusion.AFX:Image {
  49. Fusion Components - AFX Github: https://github.com/PackageFactory/atomic-fusion-afx EXPERIMENTAL CODE ... WILL

    LIKELY CHANGE ... BUT IT WORKS prototype(PackageFactory.AtomicFusion.AFX:Example) < prototype(PackageFactory.AtomicFusion:Component) { title = 'title text' subtitle = 'subtitle line' imageUri = 'https://dummyimage.com/600x400/000/fff' renderer = afx` <div> <h1 @key="headline" class="headline">{props.title}</h1> <h2 @key="subheadline" class="subheadline" @if.hasSubtitle={props.subtitle ? true : false}>{props.subtitle}</h2> <PackageFactory.AtomicFusion.AFX:Image @key="image" uri={props.imageUri} /> </div> ` }
  50. Fusion Components - AFX Github: https://github.com/PackageFactory/atomic-fusion-afx EXPERIMENTAL CODE ... WILL

    LIKELY CHANGE ... BUT IT WORKS prototype(PackageFactory.AtomicFusion.AFX:Example) < prototype(PackageFactory.AtomicFusion:Component) { title = 'title text' subtitle = 'subtitle line' imageUri = 'https://dummyimage.com/600x400/000/fff' renderer = afx` <div> <h1 @key="headline" class="headline">{props.title}</h1> <h2 @key="subheadline" class="subheadline" @if.hasSubtitle={props.subtitle ? true : false}>{props.subtitle}</h2> <PackageFactory.AtomicFusion.AFX:Image @key="image" uri={props.imageUri} /> </div> ` }
  51. Fusion Components - AFX Github: https://github.com/PackageFactory/atomic-fusion-afx EXPERIMENTAL CODE ... WILL

    LIKELY CHANGE ... BUT IT WORKS prototype(PackageFactory.AtomicFusion.AFX:Example) < prototype(PackageFactory.AtomicFusion:Component) { title = 'title text' subtitle = 'subtitle line' imageUri = 'https://dummyimage.com/600x400/000/fff' renderer = afx` <div> <h1 @key="headline" class="headline">{props.title}</h1> <h2 @key="subheadline" class="subheadline" @if.hasSubtitle={props.subtitle ? true : false}>{props.subtitle}</h2> <PackageFactory.AtomicFusion.AFX:Image @key="image" uri={props.imageUri} /> </div> ` }
  52. What to take home Don't use Partials Components in Fusion

    are a thing, use them today! Sitegeist.Monocle helps to develop reusable Components.
  53. Copyright: Larry D. Moore [CC BY-SA 3.0 oder GFDL], via

    Wikimedia Commons
  54. Copyright: By Alan Chia (Lego Color Bricks) [CC BY-SA 2.0],

    via Wikimedia Commons
  55. Copyright: elPadawan [CC BY-SA 2.0], via flickr.com/photos/elpadawan/8505316460

  56. Thank you and good luck