This package adds a styleguide module to Neos that renders the
Fusion prototypes in isolation that are annotated with @styleguide
.
- Martin Ficzel - [email protected]
- Wilhelm Behncke - [email protected]
The development and the public-releases of this package is generously sponsored by our employer http://www.sitegeist.de.
The Monocle-Module uses the real Fusion-code to render the annotated prototypes in isolation. That way the styleguide is always up to date and cannot diverge over time from the real codebase.
The Monocle was defined with Atomic-Design and pure Fusion without Fluid in mind but the implementation is Coding-Style and Template-Engine agnostic. You can use Monocle to render Fluid based Prototypes without any limitation.
Sitegeist.Monocle is available via packagist. "sitegeist/monocle" : "~4.0"
to the require section of the composer.json
or run composer require sitegeist/monocle
.
We use semantic-versioning so every breaking change will increase the major-version number.
To render a prototype as a styleguide-item it simply has to be annotated:
prototype(Vendor.Package:Components.Headline) < prototype(Neos.Fusion:Component) {
#
# styleguide annotation to define title, description and props for the styleguide
#
@styleguide {
title = 'My Custom Prototype'
description = 'A Prototype ....'
props {
content = 'Hello World'
}
propSets {
headline-2 {
tagName = 'h2'
content = 'Alternate styleguide content for h2'
}
}
}
#
# normal fusion props and renderer
#
tagName = 'h1'
content = ''
renderer = afx`
<Neos.Fusion:Tag tagName={props.tagName}>{props.content}</Neos:Fusion:Tag>
`
}
The styleguide will render the items without the usual context. The site
, documenNode
and node
context variables are not present inside the styleguide rendering by intention.
That way it is ensured that your prototypes rely only on the fusion path for rendering and are not affected by editor data. This is important for reliable testing of components.
To map an actual content-node on a component-prototype use a separate fusion prototype.
prototype(Vendor.Package:Content.Headline) < prototype(Neos.Neos:ContentComponent){
content = ${q(node).property('title')}
renderer = Vendor.Package:Components.Headline {
@apply.props = ${props}
}
}
That way the rendering prototype is completely separated from the mapping prototype and therefore highly reusable.
The distinction between rendering- and mapping-prototypes can be compared to presentational-components vs. container-components in the ReactJS world.
Some configuration is available to configure the preview.
Sitegeist:
Monocle:
preview:
#
# The fusion path that renders the preview.
# the available context is has the values
# - sitePackageKey
# - prototypeName
# - propSet
# - props
#
fusionRootPath: '/<Sitegeist.Monocle:Preview.Page>'
#
# The fusion prototype that is rendered initially
# Optional: Will default to the first found prototype
#
defaultPrototypeName: 'Vendor.Site:Prototype'
#
# The query selector that is used to extract the component html
# from the preview to the html-view.
# Optional: Default is 'body'
#
sourceQuerySelector: 'body'
To include your styles and scripts into the preview you can extend the Sitegeist.Monocle:Preview.Page
prototype the
same way you would customize Neos.Neos:Page
.
//
// Add stylesheets to to the preview-prototype
//
prototype(Sitegeist.Monocle:Preview.Page) {
head {
stylesheets.main = Vendor.Site:Resources.Styles
javascripts.main = Vendor.Site:Resources.Scripts
}
bodyScripts = Vendor.Site:Resources.BodyScripts {
@position = 'before closingBodyTag'
}
}
To configure the available viewport presets you can alter the following configuration.
Sitegeist:
Monocle:
ui:
viewportPresets:
xs:
label: 'xtra small'
width: 400
height: 600
md:
label: 'medium'
width: 600
height: 400
l:
label: 'wide'
width: 800
height: 600
If you have translations in your component you can configure the available locales via settings
Sitegeist:
Monocle:
ui:
localePresets:
en:
label: 'English'
fallback: ['en_UK', 'en']
de:
label: 'German'
fallback: ['de', 'en']
fr:
label: 'French'
Some elements of Monocle can be controlled via keyboard. All hotkeys in use can be configured via Settings. It seems though, this is not always working reliably - so please be aware, that you might experience strange side effects, when overriding the default hotkey configuration.
Sitegeist:
Monocle:
ui:
hotkeys:
openNavigation: 'ctrl+f'
closeNavigation: 'esc'
navigateUp: 'up's
navigateDown: 'down'
openPreviewInNewWindow: 'ctrl+space'
At the heart of Monocles navigation mechanism sits the prototype selector. In this component you'll find all components that are annotated with @styleguide
, grouped by configurable criteria.
A possible configuration for such a group looks like this:
Sitegeist:
Monocle:
ui:
structure:
base:
position: 100
match: Components?\.Base
label: Base
icon: icon-minus
color: '#AAA'
Under the configuration path Sitegeist.Monocle.preview.structure
, you can define an arbitrary number of component groups. Each group consists of:
- A
label
, which will be displayed as such in the UI - An
icon
, that is attached to each component in the group - A
color
, that will be applied to the icon - A
match
er - a regular expression that will be applied to the non-package part of the components prototype name and thus determines the affiliation of a component to the configured group.
Monocle ships with a default structure configuration that tries to represent an Atomic-Design-like structure. So, the configuration consists of defaults for atoms
, molecules
, organisms
and templates
.
Each component that doesn't match any of the configured groups will instead be put into the unknown
group.
If you do not want to display components, you can define hiddenPrototypeNamePatterns as follows:
Sitegeist:
Monocle:
hiddenPrototypeNamePatterns:
- 'Vendor.Site:*'
- 'Another.Vendor.Site:Prototype'
Specific components can be "unhidden" even if they match one of the hiddenPrototypeNamePatterns
patterns:
Sitegeist:
Monocle:
alwaysShowPrototypes:
- 'Vendor.Site:Some.Component.ThatShouldBeShown'
- 'Another.Vendor.Site:Prototype.ThatShouldBeShown'
This allows for including prototypes of packages selectively.
All configurations can be overwritten for each selected site package.
Sitegeist:
Monocle:
packages:
'Vendor.Site':
ui:
viewportPresets:
xxl:
label: 'extra wide'
width: 1600
height: 1000
Sitegeist.Monocle brings some fusion-prototypes that you can use or adjust to your needs.
The prototype Sitegeist.Monocle:Preview.Page
renders the preview view for a prototype, to do so it uses Sitegeist.Monocle:Preview.Prototype
below.
You can extend this prototype to add your styles and scripts as you would with Neos.Neos:Page
.
prototype(Sitegeist.Monocle:Preview.Page) {
head {
metaViewport = '<meta name="viewport" content="width=device-width">'
stylesheets.main = Neos.Fusion:Tag {
tagName = 'link'
attributes.rel = 'stylesheet'
attributes.href = Neos.Fusion:ResourceUri {
path = 'resource://Vendor.Site/Public/Styles/main.css'
}
}
javascripts.main = Neos.Fusion:Tag {
tagName = 'script'
attributes.src = Neos.Fusion:ResourceUri {
path = 'resource://Vendor.Site/Public/JavaScript/main.js'
}
}
}
}
You have to add the same header informations to Sitegeist.Monocle:Preview.Page
AND to Neos.Neos:Page
to make ensure the rendered result in the styleguide
is identical to the frontend. To do it is recommended to centralize those in fusion-components.
The prototype Sitegeist.Monocle:Preview.Prototype
is used to render a single prototype with applied styleguide props.
This is useful if you want to provide the result as prop to the preview of another prototype.
The prototyoe allows to specify the following options:
prototypeName
: string The name of the prototyoepropSet
: string the name of the propSet that is applied in addition to the default propsprops
: array key => value pairs that are applied in addition to the defaultProps and the propSet
The following example shows how the Sitegeist.Monocle:Preview.Prototype
can be used to render a preview inside of a styleguide prop:
prototype(Vendor.Site:Container) {
@styleguide{
props.content = Sitegeist.Monocle:Preview.Prototype {
prototypeName = 'Vendor.Site:Item'
propSet = 'large'
}
}
...
}
Monocle has fusion-prototypes to simulate json api responses for components.
Generic data uri implementation that expects type
and content
as string
endpointUrl = Sitegeist.Monocle:DataUri {
content = '{"hello":"world"}'
type = 'application/json'
}
The DataUri-Prototypes will encode the content as base64. Attention: Data Uris do not accept url-parameters. If you frontend code adds arguments to the mock you have to be aware of that.
For convenience special prototypes for json and text exist:
Sitegeist.Monocle:DataUri.Json
: And endpoint-mock with media-typeapplication/json
that will passcontent
trough Json.stringifySitegeist.Monocle:DataUri.Text
: And endpoint-mock with media-typetext/plain
Create an uri to an monocle endpoint that returns the passed content with the given type
endpointUrl = Sitegeist.Monocle:MirrorUri {
content = '{"hello":"world"}'
type = 'application/json'
}
Attention: Browsers will often crop the urls to a maximal length, be aware of that if you mock large json-structures.
For convenience special prototypes for json and text exist:
Sitegeist.Monocle:MirrorUri.Json
: And endpoint-mock with media-typeapplication/json
that accepts RawArray dataSitegeist.Monocle:MirrorUri.Text
: And endpoint-mock with media-typetext/plain
Create an URI that will return the content of the file and the contentType for the given key.
endpointUrl = Sitegeist.Monocle:StaticUri {
key = 'example'
}
The path and content type for each key are configured via Settings:
Sitegeist:
Monocle:
uriMock:
static:
example:
path: 'resource://Vendor.Package/Private/Json/example.json'
contentType: 'application/json'
prototype(Vendor.Package:Component.SearchExample) < prototype(Neos.Fusion:Component) {
@styleguide {
props {
endpointUrl = Sitegeist.Monocle:DataUri.Json {
content = Neos.Fusion:RawArray {
term = 'hamburch'
suggestedTerm = 'hamburg'
}
}
}
}
endpointUrl = null
renderer = afx`
<div data-endpoint-url={props.endpointUrl} />
`
}
Monocle will cache the fusion code for every site package. To invalidate this cache the the Fusion directories of all packages are monitored and changes trigger the flushing of the fusion-cache.
The setting Sitegeist.Monocle.fusion.enableObjectTreeCache
enables the caching in Monocle by default.
The monocle Routes are included automatically via Settings.
Monocle comes with four privilege targets to control access.
Sitegeist.Monocle:Backend.Styleguide
: call the backend module that will open the styleguideSitegeist.Monocle:Styleguide.Api
: request informations about prototypes etc. via api (used from the module)Sitegeist.Monocle:Styleguide.Preview
: show a preview for a prototypeSitegeist.Monocle:Styleguide.Module
: show the styleguide
- In
Production
-context all monocle privileges are by default granted to the groupNeos.Neos:AbstractEditor
. That way only backend-uses can see the styleguide. - In
Development
-context the Sitegeist.Monocle:Styleguide privileges are granted to the groupNeos.Flow:Everybody
. That way the Styleguide can be accessed without any database via url http://127.0.0.1:8081/monocle/preview/module . - For integration into ci-processes you grant access to the privileges
Sitegeist.Monocle:Styleguide.Preview
andSitegeist.Monocle:Styleguide.Api
to the ci-system.
We will gladly accept contributions. Please send us pull requests.