88 |
89 |
94 |
--------------------------------------------------------------------------------
/docs/api/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | # Fractal API documentation
6 |
7 | Fractal provides a programmatic API that allows you to [write custom commands](../guide/cli/custom-commands.html), [tie it into your build tools](../guide/integration/build-tools.html) or help with integrating your component library into your [production site or application](../guide/integration/integrating-into-production.html).
8 |
9 | If you've created a [project settings file](../guide/project-settings.html) for your project then you have already interacted with the Fractal API.
10 |
11 | ::: danger
12 | The Fractal API docs are currently very much a work in progress. Keep checking back regularly for updates!
13 | :::
14 |
15 | ## Obtaining a Fractal instance
16 |
17 | All API methods are called on an instance of Fractal or one of the objects it exposes. To get a new instance of Fractal, first `require` the `@frctl/fractal` module and then call the `.create()` method on it. In one line that looks like this:
18 |
19 | ```js
20 | const fractal = require('@frctl/fractal').create();
21 | ```
22 |
23 | You can then call API methods on this fractal instance (or on the objects it exposes) like so:
24 |
25 | ```js
26 | // set the project title
27 | fractal.set('project.title', 'My New Project');
28 | ```
29 |
30 | See the individual API documentation pages for full details of available properties and methods.
31 |
32 | ## Initial load & parse
33 |
34 | Before you can access data about any components or documentation pages via the API, you need to first call the `fractal.load()` method to tell Fractal to perform an initial parse of the relevant filesystem directories. This method is asynchronous and returns a `Promise`:
35 |
36 | ```js
37 | fractal.load().then(() => {
38 |
39 | // render a component with a custom set of context data
40 | fractal.components.render('@button', {
41 | text: 'Click here',
42 | style: 'primary-action'
43 | }).then(html => {
44 | console.log(html);
45 | });
46 |
47 | });
48 | ```
49 |
50 | This method is called behind the scenes when creating new development server instances or running CLI commands.
51 |
--------------------------------------------------------------------------------
/docs/api/endpoints/fractal-cli.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: fractal.cli
3 | ---
4 |
5 | # fractal.cli
6 |
7 | The `.cli` property on the main fractal instance provides access to utilities for working with the Fractal [CLI tool](../../guide/cli/).
8 |
9 | ```
10 | const fractal = require('@frctl/fractal').create();
11 | fractal.cli.exec('start -s');
12 | ```
13 |
14 | ### .command(commandString, callback, opts)
15 |
16 | * `commandString` - *String*
17 | * `callback` - *Function*
18 | * `opts` - *String | Object* [optional]
19 |
20 | Register a custom command to be made available to the Fractal CLI tool.
21 |
22 | ```js
23 | fractal.cli.command('foo [optionalArg]', function(args, done){
24 | console.log(args.requiredArg);
25 | done();
26 | });
27 | ```
28 |
29 | The `commandString` describes the format that your command should take, and allows you to specify required and optional arguments.
30 |
31 | The callback is a function that will be run when the command is called. The first argument it receives is a object containing the arguments parsed out of the command string, plus an object (`options`) containing any option flags that have been provided.
32 |
33 | The `opts` argument can be a string to describe the function of the command, or it can be an configuration object. For example:
34 |
35 | ```js
36 | const options = {
37 | description: 'Start a server to run an HTTP API',
38 | options: [
39 | ['-p, --port ', 'The port to run the server on.'],
40 | ]
41 | }
42 |
43 | fractal.cli.command('api', function(args, done){
44 | // start the server...
45 | console.log(`Server started on port: ${args.options.port}`);
46 | done();
47 | }, options);
48 |
49 | // Use the command: `fractal api --port=4444`
50 | ```
51 |
52 | ### .exec()
53 |
54 | Programmatically run any command that is available from the fractal CLI.
55 |
56 | ```js
57 | fractal.cli.exec('start --port=3333 --watch');
58 | ```
59 |
60 | ### .log()
61 |
62 | Log a message to the console via Fractal's CLI formatter.
63 |
64 | ```js
65 | fractal.cli.log('Just some information');
66 | ```
67 |
68 | ### .error()
69 |
70 | Log a message to the console via Fractal's CLI error formatter.
71 |
72 | ```js
73 | fractal.cli.error('Oops somthing went wrong!');
74 | ```
75 |
76 |
97 |
--------------------------------------------------------------------------------
/docs/api/endpoints/fractal-components.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: fractal.components
3 | ---
4 |
5 | # fractal.components
6 |
7 | The `.components` property on the main fractal instance provides access to the **components source** object.
8 |
9 | ```
10 | const fractal = require('@frctl/fractal').create();
11 | fractal.components.set('ext', '.html');
12 | ```
13 |
14 | ::: tip
15 | The `fractal.components` object is a _Collection_ and so inherits all the methods that are available on Collection instances in addition to those documented below. See the [Collection documentation](../entities/collection.html) for full details.
16 | :::
17 |
18 | ## Methods
19 |
20 | ### .set(path, value)
21 |
22 | * `path` - *String*
23 | * `value` - *String | Object*
24 |
25 | Set the value of a configuration setting, identified by its `path`. See the [components configuration](../../guide/components/configuration-reference.html) documentation for details of available options.
26 |
27 | ```js
28 | fractal.components.set('ext', '.html');
29 | ```
30 |
31 | ### .get(path)
32 |
33 | * `path` - *String*
34 |
35 | Get the value of a configuration setting, identified by it's `path`. For a complete list of configuration values see the [components configuration](../../guide/components/configuration-reference.html) documentation.
36 |
37 | ```js
38 | console.log(fractal.components.get('ext')); // '.html'
39 | ```
40 |
41 | ### .engine(adapter)
42 |
43 | * `adapter` - *Adapter | String*
44 |
45 | Set the [template engine adapter](../../guide/customisation/template-engines.html) to be used for rendering the component view templates.
46 |
47 | ```js
48 | fractal.components.engine('@frctl/nunjucks'); // no customisation needed, pass string of module name
49 |
50 | const nunjucks = require('@frctl/nunjucks')({
51 | // set config here
52 | });
53 | fractal.components.engine(nunjucks); // or pass in configured Adapter instance
54 | ```
55 |
56 | ### .resolve(context)
57 |
58 | * `context` - *Object*
59 |
60 | Resolve the supplied context object. Parses out and resolved `@handle` syntax data references and any promises contained in the data. Returns a `Promise`.
61 |
62 | ```js
63 | const resolvedContext = fractal.components.resolve({
64 | title: '@list.title',
65 | text: 'Some text',
66 | entries: someFunctionThatReturnsAPromise()
67 | });
68 | ```
69 |
70 | ### .on(event, callback)
71 |
72 | * `event` - *String*
73 | * `callback` - *Function*
74 |
75 | Listen out and respond to lifecycle events. See the [Events](#events) section for more details.
76 |
77 | ```js
78 | fractal.components.on('changed', function(eventData){
79 | console.log(`Change in component directory detected`);
80 | });
81 | ```
82 |
83 | ### .load()
84 |
85 | Perform an initial read and parse of the components directory. Returns a `Promise`.
86 |
87 | ```js
88 | fractal.components.load().then(() => {
89 | console.log('Finished parsing components directory!');
90 | });
91 | ```
92 |
93 | ### .watch()
94 |
95 | Start a watch task to monitor the components directory for changes.
96 |
97 | ```js
98 | fractal.components.watch();
99 | ```
100 |
101 | ### .unwatch()
102 |
103 | Stop any currently running watch tasks.
104 |
105 | ```js
106 | fractal.components.unwatch();
107 | ```
108 |
109 |
110 | ## Properties
111 |
112 | ### .label
113 |
114 | The text used to reference the components source in any navigation.
115 |
116 | ### .title
117 |
118 | The text used to reference the components source in any titles.
119 |
120 | ### .isLoaded
121 |
122 | Boolean, `true` if the initial source directory read and parse has been completed.
123 |
124 | ### .fullPath
125 |
126 | Full, resolved filesystem path to the components directory.
127 |
128 |
129 | ## Events
130 |
131 | The `fractal.components` object is an _EventEmitter_ and emits events that can be listened to via using the `.on()` method (documented above). Available events to listen for are described below:
132 |
133 | ### loaded
134 |
135 | Emitted when Fractal has finished the initial parse of the components directory.
136 |
137 | ```js
138 | fractal.components.on('loaded', function(){
139 | console.log(`Components directory has been loaded`);
140 | });
141 | ```
142 |
143 | ### changed
144 |
145 | Emitted when one or more files in the components directory are added, removed or edited, but _before_ Fractal has re-parsed the contents of the directory.
146 |
147 | ```js
148 | fractal.components.on('changed', function(eventData){
149 | console.log(`Change in components directory`);
150 | });
151 | ```
152 |
153 | * `eventData` - an event data object, e.g. `{ event: 'change', path: 'path/to/file.scss' }`
154 |
155 | ### updated
156 |
157 | Emitted when Fractal has finished re-parsing the components directory after a change.
158 |
159 | ```js
160 | fractal.components.on('updated', function(source, eventData){
161 | console.log(`Components source has been updated`);
162 | });
163 | ```
164 |
165 | * `eventData` - an event data object, e.g. `{ event: 'change', path: 'path/to/file.scss' }`
166 |
--------------------------------------------------------------------------------
/docs/api/endpoints/fractal-docs.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: fractal.docs
3 | ---
4 |
5 | # fractal.docs
6 |
7 | The `.docs` property on the main fractal instance provides access to the **documentation source** object.
8 |
9 | ```
10 | const fractal = require('@frctl/fractal').create();
11 | fractal.docs.set('ext', '.html'); // set a configuration property on the documentation source object.
12 | ```
13 |
14 | ::: tip
15 | The `fractal.docs` object is a _Collection_ and so inherits all the methods that are available on Collection instances in addition to those documented below. See the [Collection documentation](../entities/collection.html) for full details.
16 | :::
17 |
18 | ## Methods
19 |
20 | ### .set(path, value)
21 |
22 | * `path` - *String*
23 | * `value` - *String | Object*
24 |
25 | Set the value of a configuration setting, identified by its `path`. See the [docs configuration](../../guide/documentation/configuration-reference.html) documentation for details of available options.
26 |
27 | ```js
28 | fractal.docs.set('ext', '.html');
29 | ```
30 |
31 | ### .get(path)
32 |
33 | * `path` - *String*
34 |
35 | Get the value of a configuration setting, identified by it's `path`. For a complete list of configuration values see the [docs configuration](../../guide/documentation/configuration-reference.html) documentation.
36 |
37 | ```js
38 | console.log(fractal.docs.get('ext')); // '.html'
39 | ```
40 |
41 | ### .engine(adapter)
42 |
43 | * `adapter` - *Adapter | String*
44 |
45 | Set the [template engine adapter](../../guide/customisation/template-engines.html) to be used for rendering the component view templates.
46 |
47 | ```js
48 | fractal.docs.engine('@frctl/nunjucks'); // no customisation needed, pass string of module name
49 |
50 | const nunjucks = require('@frctl/nunjucks')({
51 | // set config here
52 | });
53 | fractal.docs.engine(nunjucks); // or pass in configured Adapter instance
54 | ```
55 |
56 | ### .resolve(context)
57 |
58 | * `context` - *Object*
59 |
60 | Resolve the supplied context object. Parses out and resolved `@handle` syntax data references and any promises contained in the data. Returns a `Promise`.
61 |
62 | ```js
63 | const resolvedContext = fractal.components.resolve({
64 | title: '@styleguide.title',
65 | text: 'Some text',
66 | entries: someFunctionThatReturnsAPromise()
67 | });
68 | ```
69 |
70 | ### .on(event, callback)
71 |
72 | * `event` - *String*
73 | * `callback` - *Function*
74 |
75 | Listen out and respond to lifecycle events. See the [Events](#events) section for more details.
76 |
77 | ```js
78 | fractal.docs.on('changed', function(eventData){
79 | console.log(`Change in component directory detected`);
80 | });
81 | ```
82 |
83 | ### .load()
84 |
85 | Perform an initial read and parse of the docs directory. Returns a `Promise`.
86 |
87 | ```js
88 | fractal.docs.load().then(() => {
89 | console.log('Finished parsing docs directory!');
90 | });
91 | ```
92 |
93 | ### .watch()
94 |
95 | Start a watch task to monitor the docs directory for changes.
96 |
97 | ```js
98 | fractal.docs.watch();
99 | ```
100 |
101 | ### .unwatch()
102 |
103 | Stop any currently running watch tasks.
104 |
105 | ```js
106 | fractal.docs.unwatch();
107 | ```
108 |
109 |
110 | ## Properties
111 |
112 | ### .label
113 |
114 | The text used to reference the docs source in any navigation.
115 |
116 | ### .title
117 |
118 | The text used to reference the docs source in any titles.
119 |
120 | ### .isLoaded
121 |
122 | Boolean, `true` if the initial source directory read and parse has been completed.
123 |
124 | ### .fullPath
125 |
126 | Full, resolved filesystem path to the docs directory.
127 |
128 |
129 | ## Events
130 |
131 | The `fractal.docs` object is an _EventEmitter_ and emits events that can be listened to via using the `.on()` method (documented above). Available events to listen for are described below:
132 |
133 | ### loaded
134 |
135 | Emitted when Fractal has finished the initial parse of the docs directory.
136 |
137 | ```js
138 | fractal.docs.on('loaded', function(){
139 | console.log(`Docs directory has been loaded`);
140 | });
141 | ```
142 |
143 | ### changed
144 |
145 | Emitted when one or more files in the docs directory are added, removed or edited, but _before_ Fractal has re-parsed the contents of the directory.
146 |
147 | ```js
148 | fractal.docs.on('changed', function(eventData){
149 | console.log(`Change in docs directory`);
150 | });
151 | ```
152 |
153 | * `eventData` - an event data object, e.g. `{ event: 'change', path: 'path/to/file.scss' }`
154 |
155 | ### updated
156 |
157 | Emitted when Fractal has finished re-parsing the docs directory after a change.
158 |
159 | ```js
160 | fractal.docs.on('updated', function(source, eventData){
161 | console.log(`Docs source has been updated`);
162 | });
163 | ```
164 |
165 | * `eventData` - an event data object, e.g. `{ event: 'change', path: 'path/to/file.scss' }`
166 |
--------------------------------------------------------------------------------
/docs/api/endpoints/fractal-web.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: fractal.web
3 | ---
4 |
5 | # fractal.web
6 |
7 | The `.web` property on the main fractal instance provides access to utilities for working with the development server and web-UI exporter.
8 |
9 | ```
10 | const fractal = require('@frctl/fractal').create();
11 | fractal.web.server(); // obtain a server instance.
12 | ```
13 |
14 | ### .server(config)
15 |
16 | * `config` - *Object* [optional]
17 |
18 | Obtain a new development [Server](../entities/server.html) instance. Any configuration properties passed in will be merged with the current set of global [server configuration properties](../../guide/web/configuration-reference.html),
19 |
20 | ```js
21 | const server1 = fractal.web.server();
22 | const server2 = fractal.web.server({
23 | sync: true
24 | });
25 | ```
26 |
27 | See the [Server API](../entities/server.html) documentation for details on usage.
28 |
29 | ### .builder(config)
30 |
31 | * `config` - *Object* [optional]
32 |
33 | Obtain a new [Builder](../entities/builder.html) instance. Any configuration properties passed in will be merged with the current set of global [web builder configuration properties](../../guide/web/configuration-reference.html),
34 |
35 | ```js
36 | const builder = fractal.web.builder();
37 | ```
38 |
39 | See the [Builder API](../entities/builder.html) documentation for details on usage.
40 |
41 | ### .theme(theme)
42 |
43 | * `theme` - *String | WebTheme*
44 |
45 | Set the theme to be used for the dev server and static web UI exporter.
46 |
47 | ```js
48 | fractal.web.theme('@frctl/mandelbrot'); // just use an installed package name
49 | fractal.web.theme(myTheme); // or pass in a configured instance of a WebTheme
50 | ```
51 |
52 | ### .set(path, value)
53 |
54 | * `path` - *String*
55 | * `value` - *String | Object*
56 |
57 | Set the value of a configuration setting, identified by its `path`. See the [web configuration](../../guide/web/configuration-reference.html) documentation for details of available options.
58 |
59 | ```js
60 | fractal.web.set('builder.dest', 'dist/output');
61 | ```
62 |
63 | ### .get(path)
64 |
65 | * `path` - *String*
66 |
67 | Get the value of a configuration setting, identified by it's `path`. For a complete list of configuration values see the [web configuration](../../guide/web/configuration-reference.html) documentation.
68 |
69 | ```js
70 | console.log(fractal.web.get('builder.dest')); // 'dist/output'
71 | ```
72 |
--------------------------------------------------------------------------------
/docs/api/endpoints/fractal.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: fractal
3 | ---
4 |
5 | # fractal
6 |
7 | The following properties and methods are available directly on any Fractal instance. You can get a new instance via the `.create()` convenience method when requiring the Fractal module, like so:
8 |
9 | ```js
10 | const fractal = require('@frctl/fractal').create();
11 | ```
12 |
13 | ## Methods
14 |
15 | ### .set(path, value)
16 |
17 | * `path` - *String*
18 | * `value` - *String | Object*
19 |
20 | Set the value of a configuration setting, identified by its `path`. See the [project settings](../../guide/project-settings.html) documentation for details of available options.
21 |
22 | ```js
23 | fractal.set('project.title', 'My Component Library');
24 | ```
25 |
26 | ### .get(path)
27 |
28 | * `path` - *String*
29 |
30 | Get the value of a configuration setting, identified by it's `path`. For a complete list of configuration values see the [project settings](../../guide/project-settings.html) documentation.
31 |
32 | ```js
33 | console.log(fractal.get('project.title')); // 'My Component Library'
34 | ```
35 |
36 | ### .on(event, callback)
37 |
38 | * `event` - *String*
39 | * `callback` - *Function*
40 |
41 | Listen out and respond to lifecycle events. See the [Events](#events) section for more details.
42 |
43 | ```js
44 | fractal.on('source:changed', function(source, eventData){
45 | console.log(`Change in ${source.name} directory`);
46 | });
47 | ```
48 |
49 | ### .load()
50 |
51 | Perform an initial read and parse of the relevant project directories. Returns a `Promise`.
52 |
53 | ```js
54 | fractal.load().then(() => {
55 | console.log('Finished parsing components and documentation!');
56 | });
57 | ```
58 |
59 | ### .watch()
60 |
61 | Start a watch task to monitor the relevant project directories for changes.
62 |
63 | ```js
64 | fractal.watch();
65 | ```
66 |
67 | ### .unwatch()
68 |
69 | Stop any currently running watch tasks.
70 |
71 | ```js
72 | fractal.unwatch();
73 | ```
74 |
75 | ## Properties
76 |
77 | ### .components
78 |
79 | The component source object. See the [`fractal.components`](./fractal-components.html) documentation for full details.
80 |
81 | ### .docs
82 |
83 | The documentation source object. See the [`fractal.docs`](./fractal-docs.html) documentation for full details.
84 |
85 | ### .web
86 |
87 | Provides access to web server and build related methods. See the [`fractal.web`](./fractal-web.html) documentation for full details.
88 |
89 | ### .cli
90 |
91 | Provides access to CLI related methods. See the [`fractal.cli`](./fractal-cli.html) documentation for full details.
92 |
93 | ### .version
94 |
95 | The version of the local Fractal install.
96 |
97 | ## Events
98 |
99 | The main Fractal instance emits events that can be listened to via using the `.on()` method documented above. Available events to listen for are described below:
100 |
101 | ### source:loaded
102 |
103 | Emitted when Fractal has finished the initial parse of the source directory.
104 |
105 | ```js
106 | fractal.on('source:loaded', function(source){
107 | console.log(`${source.name} has been loaded`);
108 | });
109 | ```
110 |
111 | * `source` - the source object that has finished loading
112 |
113 | ### source:changed
114 |
115 | Emitted when one or more files in a component or documentation source are added, removed or edited, but _before_ Fractal has re-parsed the contents of the source directory.
116 |
117 | ```js
118 | fractal.on('source:changed', function(source, eventData){
119 | console.log(`Change in ${source.name} directory`);
120 | });
121 | ```
122 |
123 | * `source` - the source that has had a change to one of it's files
124 | * `eventData` - an event data object, e.g. `{ event: 'change', path: 'path/to/file.scss' }`
125 |
126 | ### source:updated
127 |
128 | Emitted when Fractal has finished re-parsing the source directory after a change.
129 |
130 | ```js
131 | fractal.on('source:updated', function(source, eventData){
132 | console.log(`${source.name} has been updated`);
133 | });
134 | ```
135 |
136 | * `source` - the source object that has been updated
137 | * `eventData` - an event data object, e.g. `{ event: 'change', path: 'path/to/file.scss' }`
138 |
--------------------------------------------------------------------------------
/docs/api/entities/adapter.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Adapter
3 | ---
4 |
5 | # Adapter
6 |
7 | ::: tip Coming soon
8 | Documentation coming soon...
9 | :::
10 |
--------------------------------------------------------------------------------
/docs/api/entities/builder.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Builder
3 | ---
4 |
5 | # Builder
6 |
7 | ::: tip Coming soon
8 | Documentation coming soon...
9 | :::
10 |
--------------------------------------------------------------------------------
/docs/api/entities/collection.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Collection
3 | ---
4 |
5 | # Collection
6 |
7 | Collection objects provide a set of utility methods for working with groups of items, such as components or documentation pages.
8 |
9 | ::: warning
10 | It's important to note that Collection objects are _immutable_ - when you call a filter method or similar you get back a new Collection object, leaving the original object intact.
11 | :::
12 |
13 | The documentation below assumes that you already have a reference to a collection object, such as the component source object:
14 |
15 | ```
16 | const collection = fractal.components;
17 | ```
18 |
19 | Collections are themselves _iterators_, so you can iterate over them directly using expressions such as the new ES2015 `for...of` loops:
20 |
21 | ```js
22 | for (let item of collection) {
23 | console.log(item.handle);
24 | }
25 | ```
26 |
27 | Collections can contain sub-collections within them. If you want to iterate over _all_ items in a collection (as opposed to only the collection's direct children) you can use the `.flatten()` method:
28 |
29 | ```js
30 | for (let item of collection.flatten()) {
31 | console.log(item.handle);
32 | }
33 | ```
34 |
35 | ## Methods
36 |
37 | ### .find(args...)
38 |
39 | Find an item within the collection. Search is recursive down through any sub-collections.
40 |
41 | ```js
42 | const button = collection.find('@button');
43 | const sameButton = collection.find('handle', 'button');
44 | const sameButtonAgain = collection.find(function(item){
45 | return item.handle === 'button';
46 | });
47 | ```
48 |
49 | ### .filter(predicate...)
50 |
51 | Returns a new collection that is the result of filtering the old collection using the `predicate`arguments.
52 |
53 | ```js
54 | const hiddenItems = collection.filter('isHidden', true);
55 | const taggedWithFoo = collection.filter(function(item){
56 | return item.tags.includes('foo');
57 | });
58 | ```
59 |
60 | ### .flatten()
61 |
62 | Return a new collection created by recursing down through the original collections items and all its sub-collections and extracting out all non-collection entities.
63 |
64 | ```js
65 | const allItems = collection.flatten();
66 | ```
67 |
68 | ### .flattenDeep()
69 |
70 | Same as flatten, except in the case of component collections will also pull out any variants of the components as well as the root components themselves.
71 |
72 | ```js
73 | const allVariants = collection.flattenDeep();
74 | ```
75 |
76 | ### .orderBy(args...)
77 |
78 | Returns a new collection that is the result of ordering the old collection using according to the arguments supplied.
79 |
80 | ```js
81 | const subCollectionsFirstThenByTitle = collection.orderBy(['isCollection', 'title'], ['asc', 'asc']);
82 | ```
83 |
84 | ### .forEach(callback)
85 |
86 | Iterate over all of the items in the collection, calling the callback for each one.
87 |
88 | ```js
89 | collection.forEach(function(item){
90 | console.log(item.title);
91 | });
92 | ```
93 |
94 | ### .map(callback)
95 |
96 | Return a new collection made up of mapped items from the source collection.
97 |
98 | ```js
99 | const newCollection = collection.forEach(function(item){
100 | collection.title = collection.title.toUpperCase();
101 | return collection;
102 | });
103 | ```
104 |
105 | ### .first()
106 |
107 | Get the first item in the collection
108 |
109 | ```js
110 | const first = collection.first();
111 | ```
112 |
113 | ### .last()
114 |
115 | Get the last item in the collection
116 |
117 | ```js
118 | const first = collection.last();
119 | ```
120 |
121 | ### .eq(pos)
122 |
123 | * `pos`: **Integer**
124 |
125 | Get the item at position `pos` in the collection (collections are zero-indexed).
126 |
127 | ```js
128 | const third = collection.eq(2);
129 | ```
130 |
131 | ### .toArray()
132 |
133 | Converts the collection to an array of items, as opposed to an iteratable object.
134 |
135 | ```js
136 | const items = collection.toArray();
137 | ```
138 |
139 | ### .toJSON()
140 |
141 | Returns a simplified, 'template engine friendly' object representation of the collection and all it's children, recursively.
142 |
143 | ```js
144 | const items = collection.toJSON();
145 | ```
146 |
147 | ### .toStream()
148 |
149 | Turns the collection into a Gulp-compatible Vinyl stream.
150 |
151 | ```js
152 | const stream = collection.toStream();
153 | ```
154 |
155 |
156 | ## Properties
157 |
158 | ### .size
159 |
160 | The number of items in the collection (does **not** include items within sub-collections).
161 |
--------------------------------------------------------------------------------
/docs/api/entities/component-collection.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Component Collection
3 | ---
4 |
5 | # Component Collection
6 |
7 | ::: tip Coming soon
8 | Documentation coming soon...
9 | :::
10 |
--------------------------------------------------------------------------------
/docs/api/entities/component.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Component
3 | ---
4 |
5 | # Component
6 |
7 | ::: tip Coming soon
8 | Documentation coming soon...
9 | :::
10 |
--------------------------------------------------------------------------------
/docs/api/entities/doc-collection.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Doc Collection
3 | ---
4 |
5 | # Doc Collection
6 |
7 | ::: tip Coming soon
8 | Documentation coming soon...
9 | :::
10 |
--------------------------------------------------------------------------------
/docs/api/entities/doc.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Doc
3 | ---
4 |
5 | # Doc
6 |
7 | ::: tip Coming soon
8 | Documentation coming soon...
9 | :::
10 |
--------------------------------------------------------------------------------
/docs/api/entities/server.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Server
3 | ---
4 |
5 | # Server
6 |
7 | ::: tip Coming soon
8 | Documentation coming soon...
9 | :::
10 |
--------------------------------------------------------------------------------
/docs/api/entities/web-theme.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: WebTheme
3 | ---
4 |
5 | # WebTheme
6 |
7 | ::: tip Coming soon
8 | Documentation coming soon...
9 | :::
10 |
--------------------------------------------------------------------------------
/docs/guide/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | # Fractal User Guide
6 |
7 | Fractal is a tool to help you **build** and **document** web component libraries, and then **integrate** them into your projects.
8 |
9 | Component (or pattern) libraries are a way of designing and building websites in a modular fashion, breaking up the UI into small, reusable chunks that can then later be assembled in a variety of ways to build anything from larger components right up to whole pages.
10 |
11 | Fractal helps you assemble, preview and document website component libraries, and then integrate them into your web sites, apps and build processes to create joined up, 'living' projects.
12 |
13 | Fractal can be run from the command line or integrated into your project via its API.
14 |
15 |
41 |
42 | ## Requirements
43 |
44 | You'll need a [supported LTS version](https://github.com/nodejs/Release) of Node. Fractal may work on unsupported versions, but there is no active support from Fractal and new features may not be backwards compatible with EOL versions of Node.
45 |
46 | ## Why Fractal?
47 |
48 | Existing tools to help you build these component libraries often force you to use a particular template language, a specific build tool or a pre-determined way to organise the individual elements within your library. They generate a web preview to allow you to browse your rendered components, but generally aren't able to help much when it comes to integrating your component library into your build process or live site.
49 |
50 | **Fractal is different:**
51 |
52 | * **Flexible**: Complete freedom to use whichever templating language, build tool and organisational model best suits your project. Build your components using the same tools that you use for your production site.
53 | * **Integrated**: Fractal can help you seamlessly integrate your component library into your site, app or build tools by including it as a dependency in your build. Custom commands and API integration can help you build a smart, component-focussed workflow to ensure your component library is a living part of your application.
54 | * **Data-driven**: Component preview data can be hardcoded or dynamically generated any way you like - for instance using libraries such as Faker or from HTTP API calls.
55 |
56 | The web UI provides a web-based way to browse your component library, either running as a local web server or as a static HTML export. A powerful theme API means you can create your own web UI themes from scratch or by customising the default theme to your liking.
57 |
58 | A companion CLI tool helps make running tasks and adding your own CLI commands built upon the Fractal API quick and easy.
59 |
60 |
61 | ## About this guide
62 |
63 | This guide will assume basic knowledge of the command line, Node.js and how to use NPM to install and manage project dependencies.
64 |
--------------------------------------------------------------------------------
/docs/guide/cli/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | # Fractal CLI Tool
6 |
7 | The Fractal CLI tool is an optional, globally-installed NPM package that provides some useful commands for working with Fractal projects.
8 |
9 | ## Installation & setup
10 |
11 | The Fractal CLI tool can be installed globally via NPM:
12 |
13 | ```bash
14 | npm i -g @frctl/fractal
15 | ```
16 |
17 | To use the CLI tool with your Fractal project, you must first make sure you have a [project settings file](../project-settings.html) (typically called `fractal.config.js`) in the root of your project directory. This file should export a configured Fractal instance. For example:
18 |
19 | ```javascript
20 | // fractal.config.js
21 |
22 | var fractal = require('@frctl/fractal').create();
23 | fractal.set('project.title', 'FooCorp Component Library');
24 | fractal.components.set('path', __dirname + '/src/components');
25 |
26 | module.exports = fractal; // export the configured Fractal instance for use by the CLI tool.
27 | ```
28 |
29 | ## Running commands
30 |
31 | Commands are run from the command line, and typically take the format:
32 |
33 | ```bash
34 | fractal [args] [opts]
35 | ```
36 |
37 | For example, to start the web UI dev server using the BrowserSync option, you can use the command:
38 |
39 | ```bash
40 | fractal start --sync
41 | ```
42 |
43 | When running commands in this format, the command will run and then immediately exit (unless it is watching or running a server in the background).
44 |
45 | ::: tip
46 | Fractal also provides a more immersive [interactive mode](./interactive-mode.html) that makes running multiple commands easier and faster.
47 | :::
48 |
49 | ## Command types
50 |
51 | The Fractal CLI supports two different types of command - _global_ and _project-level_ commands.
52 |
53 | ### Global commands
54 |
55 | Global commands can be run from anywhere *outside of a project folder*. An example of a global command is the `fractal new ` command which helps you quickly create a new Fractal project file structure.
56 |
57 | ### Project commands
58 |
59 | Project-level commands must be run from within the root directory of your project, and require the presence of a [project settings file](../project-settings.html) in the root of the project directory.
60 |
61 | An example of a project-level command would be the `fractal start` command that starts up the [project settings file](../web/development-server.html) for the web UI.
62 |
63 |
66 |
--------------------------------------------------------------------------------
/docs/guide/cli/commands-reference.md:
--------------------------------------------------------------------------------
1 | ---
2 | label: Commands reference
3 | ---
4 |
5 | # Commands reference
6 |
7 | ## Project commands
8 |
9 | The default installation of the Fractal CLI tool provides a number of project-level commands:
10 |
11 | ### start
12 |
13 | Start a web UI local development server. See the [dev server documentation](../web/development-server.html) for more details and options.
14 |
15 | ```bash
16 | fractal start
17 | ```
18 |
19 | Available options:
20 |
21 | * `-p, --port ` - the port number to use, for example `5000`.
22 | * `-t, --theme ` - the custom theme to use.
23 | * `-s, --sync` - whether to use the integrate [BrowserSync](../web/development-server.html#browsersync-integration) instance to provide auto-refresh and syncing capabilities
24 | * `-w, --watch` - whether to watch components and documentation pages for changes
25 |
26 | ### build
27 |
28 | Export a static HTML version of the web UI into a directory in the root of your project. See the [HTML export docs](../web/exporting-static-html.html) for more details and options.
29 |
30 | ```bash
31 | fractal build
32 | ```
33 |
34 | Available options:
35 |
36 | * `-t, --theme ` - the custom theme to use.
37 |
38 | ### help
39 |
40 | Show help info, including a list of all available commands.
41 |
42 | ```bash
43 | fractal help
44 | ```
45 |
46 | ## Global commands
47 |
48 | The default installation of Fractal CLI tool provides one **global** command. Note that global commands *cannot* be run when in [interactive mode](./interactive-mode.html) or within an existing Fractal project.
49 |
50 | ### new
51 |
52 | Create a new Fractal project skeleton. Sets up the basic file structure (including creating a basic `fractal.config.js` project settings file) for you.
53 |
54 | ```bash
55 | fractal new
56 | ```
57 |
58 | The `directory-name` argument will determine the name of the directory to create. It can be a relative path name, too - for instance `example/my-new-project`.
59 |
--------------------------------------------------------------------------------
/docs/guide/cli/custom-commands.md:
--------------------------------------------------------------------------------
1 | ---
2 | label: Custom commands
3 | ---
4 |
5 | # Custom commands
6 |
7 | It is possible to extend the Fractal CLI tool using custom commands. These allow you to hook into the power of Fractal's API to build bespoke commands to help you with your project workflow.
8 |
9 | Custom commands are typically registered in your [project settings file](../project-settings.html) using the [`fractal.cli.command()`](../../api/endpoints/fractal-cli.html#command-commandstring-callback-opts) method. Once registered they can then be called via the command line or programmatically.
10 |
11 | ## An example custom command
12 |
13 | A simple custom command to list all the components in the project, together with their status, is shown below. This would typically be registered in your [project settings file](../project-settings.html).
14 |
15 | ```js
16 | // fractal.config.js
17 |
18 | var config = {
19 | description: 'Lists components in the project'
20 | };
21 |
22 | function listComponents(args, done){
23 | const app = this.fractal;
24 | for (let item of app.components.flatten()) {
25 | this.log(`${item.handle} - ${item.status.label}`);
26 | }
27 | done();
28 | };
29 |
30 | fractal.cli.command('list-components', listComponents, config); // register the command
31 | ```
32 |
33 | Once created, the command can be run from within the project directory using the command:
34 |
35 | ```bash
36 | fractal list-components
37 | ```
38 |
39 | It can also be called programmatically using the [`fractal.cli.exec()`](../../api/endpoints/fractal-cli.html#exec) method:
40 |
41 | ```js
42 | fractal.cli.exec('list-components');
43 | ```
44 |
45 | ## Accepting arguments
46 |
47 | The first argument passed to the `fractal.cli.command()` method describes the format that your command should take.
48 |
49 | * **Required arguments** can be specified by surrounding the name with angle brackets, e.g. ``.
50 | * **Optional arguments** can be specified by surrounding the name with square brackets e.g. `[foo]`.
51 |
52 | For example:
53 |
54 | ```js
55 | fractal.cli.command('foo [optionalArg] [anotherOptionalArg]', function(args, done){
56 | console.log(args.requiredArg);
57 | done();
58 | });
59 | ```
60 |
61 | The values for the arguments supplied when the command is run will be made available to the callback function within the firs `args` object.
62 |
63 | ## Accepting options
64 |
65 | You can specify available options by adding them to the config object that can be provided as the third argument when registering a command:
66 |
67 | ```js
68 | var config = {
69 | options: [
70 | ['-p, --port ', 'The port to use.'],
71 | ]
72 | };
73 |
74 | fractal.cli.command('foo', function(args, done){
75 | // do something
76 | console.log(`Something was started on port ${args.options.port}`);
77 | done();
78 | }, config);
79 | ```
80 |
--------------------------------------------------------------------------------
/docs/guide/cli/interactive-mode.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Interactive Mode
3 | ---
4 |
5 | # Interactive Mode
6 |
7 | As well as exposing 'traditional' terminal commands, Fractal also provides an *interactive CLI* for you to work with on your projects. This greatly speeds up running commands and allows you to do things like start a dev server instance and then still be able to run subsequent commands in the same CLI window.
8 |
9 | You launch the interactive CLI by running the `fractal` command in your terminal. This will drop you into interactive mode, and you should see an info box appear in your terminal, with a prompt beneath it.
10 |
11 | You can tell when you are in interactive mode because your terminal prompt will look like this:
12 |
13 | ```bash
14 | fractal ➤
15 | ```
16 |
17 | You can now enter commands to interact with your fractal project.
18 |
19 | ## Running commands
20 |
21 | Commands in interactive mode are identical to the [standard-format commands](./commands-reference.html), except that you no longer need to prefix them with `fractal`.
22 |
23 | For example, to start the dev server when in interactive mode, just use the `start` command. Flags can be used as per usual:
24 |
25 | ```bash
26 | start --sync
27 | ```
28 |
29 | ::: tip
30 | Servers will run in the background without blocking the CLI so you can start a dev server instance and then run multiple subsequent commands without having to open up a new terminal window.
31 | :::
32 |
33 | ## Interactive CLI tips
34 |
35 | * You can use the `help` command at any point to show all the available commands.
36 | * To **exit** the interactive CLI and go back into your 'regular' terminal, use the `exit` command.
37 | * Global (as opposed to project-level) commands cannot be run from within the interactive CLI.
38 |
--------------------------------------------------------------------------------
/docs/guide/collections/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | # Collections
6 |
7 | Collections are just groups of related components or documentation pages. When you create a directory that contains one or more components or pages inside it, you have created a collection.
8 |
9 | However beyond just grouping items, collections are useful because they can have their own [configuration files](../core-concepts/configuration-files.html) within which you can specify properties that will then be **applied to all child items** within that collection, saving you from having to specify them on each item. Of course, individual components, pages (or indeed sub-collections) can still [override these defaults](../core-concepts/configuration-files.html#configuration-inheritance) on a case-by-case basis if needed.
10 |
11 | ## Configuration files
12 |
13 | A collection configuration file follows the same rules as component and documentation page configuration files. It must reside in the collection directory and have the same name as the directory itself, followed by `.config.{js|json|yml}`, depending on the format.
14 |
15 | So a component collection called 'layouts' could have a YAML configuration file called `layouts.config.yml`:
16 |
17 | ```
18 | ├── components
19 | │ ├── layouts
20 | │ │ ├── layouts.config.yml
21 | │ │ ├── full-screen.hbs
22 | │ │ └── sidebar.hbs
23 | ```
24 |
25 | A sample collection configuration file contents might look like this:
26 |
27 | ```yaml
28 | title: "Website Layouts"
29 | status: "ready"
30 | context:
31 | title: "My Website"
32 | ```
33 |
34 | ### Available config properties
35 |
36 | The [collection configuration reference](./configuration-reference.html) contains full details of all the collection properties available for use.
37 |
38 | ## Ordering collections
39 |
40 | A collection can be given an order by which to sort it with regards to its siblings. This can be done by using the `order` property in the collection's configuration file, or it can be done by prefixing the collection directory name with a **two-digit number** (with leading zero, if required) **followed by a hyphen**. For example:
41 |
42 | ```
43 | ├── components
44 | │ ├── 01-patterns
45 | │ │ └── article.hbs
46 | │ └── 02-layouts
47 | │ └── sidebar.hbs
48 | ```
49 |
50 | ## Hiding collections
51 |
52 | A collection can be hidden from navigation and listings by using the `hidden` property in its configuration file or by prefixing the collection directory name with an underscore like this:
53 |
54 | ```
55 | ├── components
56 | │ ├── _layouts
57 | │ │ └── sidebar.hbs
58 | │ └── patterns
59 | │ └── article.hbs
60 | ```
61 |
62 | In this case the `layouts` collection would not show up in any navigation, but the `patterns` collection would.
63 |
64 | ::: tip Note
65 | Any components or variants *within* hidden collections can still be referenced by other components, included in templates etc.
66 | :::
67 |
68 | ::: tip
69 | You can also combine *ordering* and *hiding* by constructing a directory name such as `_01-patterns`.
70 | :::
71 |
--------------------------------------------------------------------------------
/docs/guide/collections/configuration-reference.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Configuration reference
3 | ---
4 |
5 | # Collection configuration
6 |
7 | Collection configuration files can specify a number of properties. Some of these apply to the collection itself, while other 'heritable' properties act instead as 'default' values for items contained within the collection.
8 |
9 | See the [configuration inheritance](../core-concepts/configuration-files.html#configuration-inheritance) documentation for more details on this process works in practice.
10 |
11 | ## Collection properties
12 |
13 | The following properties apply directly to the collection itself, and will not be inherited by children of the collection.
14 |
15 | #### hidden
16 |
17 | Whether or not the collection (and all its children) should be hidden from listings and navigation.
18 |
19 | ```yaml
20 | hidden: false
21 | ```
22 |
23 | #### label
24 |
25 | The label is typically displayed in any UI navigation items that refer to the collection. Defaults to a title-cased version of the collection directory name if not specified.
26 |
27 | ```yaml
28 | label: 'Website Layouts'
29 | ```
30 |
31 | #### order
32 |
33 | An integer order value, used when sorting collections. Overrides any order value set as a property of the directory name if set.
34 |
35 | ```yaml
36 | order: 4
37 | ```
38 |
39 | #### title
40 |
41 | The string that is used when a UI needs a title for the collection. Defaults to the value of `label` if not set.
42 |
43 | ```yaml
44 | title: 'My Favourite Website Layouts'
45 | ```
46 |
47 | #### root
48 |
49 | Pull the collection to the navigation top level, next to the defaults "Components" and "Documentation".
50 |
51 | ```yaml
52 | root: true
53 | ```
54 |
55 | ::: warning
56 | `root` option is available only for component collections, it won’t work for documentation.
57 | :::
58 |
59 | ## Heritable properties
60 |
61 | The majority of properties set in a collection configuration file apply not to the collection itself, but instead act as defaults which cascade down to the items within it.
62 |
63 | **For details on the available cascading configuration properties** that will apply to child items, see the relevant configuration reference sections:
64 |
65 | * [Component collections](../components/configuration-reference.html#collection-properties)
66 | * [Documentation collections](../documentation/configuration-reference.html#collection-properties)
67 |
--------------------------------------------------------------------------------
/docs/guide/components/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | # Components
6 |
7 | 'Component' is a generic term used by Fractal to describe individual pieces of your website's UI.
8 |
9 | **Fractal considers every piece of your markup to be a component**. A component could be a tiny chunk of HTML for a text input, it could be a whole page or it could be something in between.
10 |
11 | Unlike some other systems, Fractal does not enforce any specific nomenclature or taxonomy on your components - you are free to organise and name them as you wish.
12 |
13 | ## What defines a component?
14 |
15 | In order for Fractal to recognise your components, they must:
16 |
17 | 1. Live within the component directory that you specified in your [project settings](../project-settings.html).
18 | 2. Have a 'view' file, containing the markup required to render your component. This should have a file extension that matches the one specified in your [project settings](../project-settings.html) (if not specified, the default is `.hbs`).
19 |
20 | Optionally, components can also:
21 |
22 | * Have per-component configuration and preview data.
23 | * Be organised into directories and sub-directories as required.
24 | * Include as many related files (such as JavaScript, CSS, tests and READMEs) as you like.
25 | * Have one or more *variants* - useful for when you have a component which needs to have a number of very similar instances.
26 |
27 | The markup for a component can either be written as 'vanilla' HTML or using a template language of your choosing. By default, Fractal expects that you are using [Handlebars](http://handlebarsjs.com) templates for your component view files, and that these files will have a `.hbs` file extension.
28 |
29 | ::: tip
30 | The [view templates](../core-concepts/view-templates.html) documentation contains more details on the default Handlebars instance and the [template engine customisation](../customisation/template-engines.html) documentation has full details how to use and configure alternative template engines with Fractal.
31 | :::
32 |
33 | Components can be created in two ways. The simplest component is just as a single file containing your markup, whilst more complex, 'compound' components can be created as a directory of associated files.
34 |
35 | ## Simple components
36 |
37 | The simplest possible component consists of just a single [view template](../core-concepts/view-templates.html). The name of the component will be taken to be the name of that file, minus the file extension.
38 |
39 | So a `button.hbs` file in the components directory will be identified as a component with the name of 'button'.
40 |
41 | ```
42 | ├── components
43 | │ └── button.hbs
44 | ```
45 |
46 | Simple components can have [configuration files](../core-concepts/configuration-files.html) associated with them. These must reside in the same directory and have the same name as the component but have a `.config.{js|json|yml}` file extension. So a JSON configuration file for the button component would be called `button.config.json`.
47 |
48 | ```
49 | ├── components
50 | │ ├── button.config.json
51 | │ └── button.hbs
52 | ```
53 |
54 | The one caveat regarding naming simple components is that they **must not have the same name as the parent folder** that contains them. This is to prevent them being identified as 'compound' components.
55 |
56 | ## Compound components
57 |
58 | Compound components allow you to group associated files (such as asset files, tests, READMEs etc) along with your primary component files.
59 |
60 | The simplest compound component consists of a directory containing a single [view template](../core-concepts/view-templates.html). The name of this view file **must** match the name of the directory. A 'block quote' component might therefore look like this:
61 |
62 | ```
63 | ├── components
64 | │ └── blockquote
65 | │ └── blockquote.hbs
66 | ```
67 |
68 | [Configuration files](../core-concepts/configuration-files.html) can of course be added, again following the same naming convention (`[component-name].config.{js|json|yml}`). Other files added to the directory will then be associated with the component. These files do not have to adhere to any particular naming convention. So a full example may look like:
69 |
70 | ```
71 | ├── components
72 | │ └── blockquote
73 | │ │ ├── blockquote.config.yml
74 | │ │ ├── blockquote.hbs
75 | │ │ ├── fancy-quote.js
76 | │ │ ├── README.md
77 | │ │ └── styles.css
78 | ```
79 |
80 | ## Referencing components
81 |
82 | When using Fractal, components (and their variants) are not referenced by their *path*, but instead by their **handle**. A handle is a bit like an ID, and using it instead of a file path means that you can move your components around without having to make updates to files that they are referenced in.
83 |
84 | Handles take the form:
85 |
86 | ```js
87 | @component-name // component
88 | @component-name--variant-name // variant - note the double hyphen seperator.
89 | ```
90 |
91 | And can be used in many places, such as when including another component via a partial. For instance, one component may include another component like this:
92 |
93 | ```handlebars
94 |
95 |
Parent component
96 | {{> @child-component}}
97 |
98 | ```
99 |
100 | Other places that handles are used include when specifying a [preview layout](./preview-layouts.html) for a component or when referencing another components [context data](../core-concepts/context-data.html).
101 |
102 | ::: tip
103 | See the documentation on [naming & referencing](./notes.html) for more details on working with handles in Fractal.
104 | :::
105 |
106 | ## Ordering components
107 |
108 | A component can be given an order by which to sort it with regards to its siblings. This can be done by using the `order` property in the components's configuration file, or it can be done by prefixing the component file name (or the parent folder name for compound components) with a **two-digit number** (with leading zero, if required) **followed by a hyphen**. For example:
109 |
110 | ```
111 | ├── components
112 | │ ├── 01-blockquote.hbs
113 | │ ├── 02-link-list
114 | │ │ └──link-list.hbs
115 | ```
116 |
117 | ## Hiding components
118 |
119 | A component can be hidden from navigation and listings by using the `hidden` property in its configuration file or by prefixing its file name (or the parent folder name for compound components) with an underscore like this:
120 |
121 | ```
122 | ├── components
123 | │ ├── _blockquote.hbs
124 | │ ├── _link-list
125 | │ │ └──link-list.hbs
126 | │ └── article.hbs
127 | ```
128 |
129 | In this case the `blockquote` and `link-list` components would **not** show up in any navigation, but the `article` component would.
130 |
131 | ::: tip
132 | Any hidden components or variants can still be referenced by other components, included in templates etc, but will not be included in any navigation or similar.
133 | :::
134 |
135 | ::: tip
136 | You can also combine *ordering* and *hiding* by constructing a file name such as `_01-article.hbs`.
137 | :::
138 |
--------------------------------------------------------------------------------
/docs/guide/components/creating-a-component.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Creating a Component
3 | ---
4 |
5 | # Creating a component
6 |
7 | The following guide will walk you through the process of creating a simple static component, making it dynamic by passing data into the view file and then building it out into a more complete example of a component.
8 |
9 | It's important to note that all components _must_ reside within your components directory for Fractal to find them. The location of this directory can be set in your [project settings](../project-settings.html) as follows:
10 |
11 | ```js
12 | fractal.components.set('path', __dirname + '/components');
13 | ```
14 |
15 | ::: tip Note
16 | All examples in this documentation will assume that you are using `/components` as your component directory and Handlebars as your [template engine](../core-concepts/view-templates.html).
17 | :::
18 |
19 |
20 | ## Creating the view file
21 |
22 | The most basic component just consists of a single markup (view) file with the appropriate file extension (i.e. `.hbs`) for the template engine you are using.
23 |
24 | As an example, let's create a simple blockquote component. To do this, we'll create a file called `blockquote.hbs` at the top level of our components directory. So our component directory file tree will look something like this:
25 |
26 | ```
27 | ├── components
28 | │ └── blockquote.hbs
29 | ```
30 |
31 | For now, let's just use plain HTML for the contents of `blockquote.hbs`. We'll add some template tags later:
32 |
33 | ```html
34 |
35 |
This is a quote! Something witty should probably go here.
36 | Mr. A. Nonymous
37 |
38 | ```
39 |
40 | Now start the [Fractal web server](../web/development-server.html) (if it's not already running) using the `fractal start` command in your terminal and point your browser to [http://localhost:3000/components/detail/blockquote](http://localhost:3000/components/detail/blockquote) (note that your port number may be different). You should see a rendered preview of your component followed by the HTML source code.
41 |
42 | **Congratulations!** :tada: You've just created your first component.
43 |
44 | ## Passing data to your view
45 |
46 | The above example works just fine but is probably not very useful. In reality, you may want to include that component in a number of places in your site, and you probably want the text content of the component to be different each time. So let's look at how we can achieve that.
47 |
48 | First you will need to replace the text in your view file with variable placeholders. In Handlebars (and many other template languages), these placeholders look like `{{variableName}}`, so our `blockquote.hbs` file could be amended to look something like this:
49 |
50 | ```handlebars
51 |
52 |
{{text}}
53 | {{citation}}
54 |
55 | ```
56 |
57 | So now we just need a way to specify the data that should be passed to our view when rendering it as a preview. This is done by creating a **component configuration file**.
58 |
59 | [Configuration files](../core-concepts/configuration-files.html) can be written as JSON, YAML or as a CommonJS JavaScript module that returns a JSON object. For this example we'll be using [YAML](http://www.yaml.org/) but check out the full component configuration docs for details on using other data formats. Configuration files must reside in the same directory as the component they are intended to configure, and for YAML files must have a filename that looks like `component-name.config.yml` (replacing `component-name` with the name of your component).
60 |
61 | So let's create a config file, called `blockquote.config.yml` for our blockquote component. Our file tree now looks like:
62 |
63 | ```
64 | ├── components
65 | │ ├── blockquote.config.yml
66 | │ └── blockquote.hbs
67 | ```
68 |
69 | And the contents of our `blockquote.config.yml` file should look a little something like this:
70 |
71 | ```yaml
72 | context:
73 | text: "Blockquotes are the best!"
74 | citation: "Fractal Docs"
75 | ```
76 |
77 | All the data in the `context` object will be passed to your template view when rendering it as a preview in the Fractal UI. You can see that the keys (`text` and `citation`) match the variable placeholder names in our template. You can also include deeply nested objects here if needed and they will be accessible to the template via dot notation (or by however your chosen template language provides access to them, if not using Handlebars).
78 |
79 | If you refresh your browser you should now see your component preview rendered with the data that you specified in the configuration file. You'll also notice that the code view browser below the preview now also shows the rendered HTML as previously, but also now includes the template file contents and the context data (displayed as JSON).
80 |
81 | ## Providing additional configuration
82 |
83 | As well as being used to specify context data to pass to your component's view template, the config file can also be used to customise other features of your component or to specify things like implementation notes for displaying in the UI.
84 |
85 | For example, if we want to customise the title (displayed at the top of the component page) or the status (more on statuses, including specifying your own, later!) of our blockquote component, we can update our config file as follows:
86 |
87 | ```yaml
88 | title: "A simple blockquote component"
89 | status: wip
90 | context:
91 | text: "Blockquotes are the best!"
92 | citation: "Fractal Docs"
93 | ```
94 |
95 | If you now refresh the page in your browser, you should see that the title and the status indicator for your blockquote component have now both changed.
96 |
97 | ::: tip
98 | There are **plenty more configuration options** for components - check out the [component configuration](./configuration-reference.html) docs for full details.
99 | :::
100 |
101 | ## Creating variants
102 |
103 | Variants are useful for when you have a need for a slightly modified version of your component, but when the change is small enough that it doesn't really warrant creating a whole separate component.
104 |
105 | ::: tip
106 | Variants can be thought of as roughly analogous to the concept of 'modifiers' in [BEM](http://getbem.com/). If you would use a BEM modifier class to describe your (sub)component, it's probably a good fit to be a variant.
107 | :::
108 |
109 | There are a number of ways to create variants, each with their own pros and cons, but probably the simplest way is to create a separate variant view file. (For full details on creating and using variants see the full [variants documentation](./variants.html)).
110 |
111 | To create a variant, add another file into your components directory, called `blockquote--fancy.hbs`. Note the `--` part of the file name - this identifies the file as a variant, and will be parsed as a variant with the name `fancy` that belongs to the `blockquote` component.
112 |
113 | So our file tree now looks like this:
114 |
115 | ```
116 | ├── components
117 | │ ├── blockquote.config.yml
118 | │ ├── blockquote--fancy.hbs
119 | │ └── blockquote.hbs
120 | ```
121 |
122 | If you refresh the web preview UI in your browser again you should see that a variant has appeared on the blockquote component page.
123 |
124 | ## Adding a preview layout
125 |
126 | [Preview layouts](./preview-layouts.html) are templates that wrap your components to allow them to be rendered in the context of 'proper' HTML page. That means that you can include links to your CSS or JavaScript files just as you would in your site proper.
127 |
128 | Preview layouts are themselves components. That means you can use your actual site 'skeleton' component (if you have one), or you can create a separate one just for the purpose of wrapping your component previews. In this example, we are going to do the latter and create a component called `_preview.hbs` in the root of our component directory, like so:
129 |
130 | ```
131 | ├── components
132 | │ ├── _preview.hbs
133 | │ ├── blockquote.config.yml
134 | │ ├── blockquote--fancy.hbs
135 | │ └── blockquote.hbs
136 | ```
137 |
138 | The `_` underscore prefixing the filename tells Fractal that this is a 'hidden' file, which means it will not show up in any component listings but can still be used as a preview layout (or included into other components). It's **not** mandatory that your preview layout components are hidden, but you may choose to do so if you like.
139 |
140 | The preview layout itself may look something like this:
141 |
142 | ```handlebars
143 |
144 |
145 |
146 |
147 |
148 | Preview
149 |
150 |
151 |
152 | {{{ yield }}}
153 |
154 |
155 |
156 |
157 | ```
158 |
159 | ::: v-pre
160 | Note the `{{{ yield }}}` placeholder - this is where the rendered content of your component will be inserted when generating the preview.
161 | :::
162 |
163 | The last thing to do is to let Fractal know that this preview layout should be used as the default layout for our components. To do this we can set a [global configuration option](./configuration-reference.html#global-configuration-options) in our [project settings](../project-settings.html) file.
164 |
165 | ```js
166 | fractal.components.set('default.preview', '@preview');
167 | ```
168 |
169 | ::: tip
170 | Note the way that we reference the preview layout using the special identifier `@preview`. This is called the component's 'handle'. You can read more details on using component and variant handles on the [components overview](../components/) page.
171 | :::
172 |
173 | Now whenever your component is rendered as a preview (for example in the web UI) it will be wrapped in your preview layout.
174 |
175 | ## Associating related files
176 |
177 | In a real-life situation, components will often have more than just markup associated with them. They will likely have some styles, some JavaScript and other files like tests and so on.
178 |
179 | In order to associate files with our blockquote component, we will need to turn it into a 'compound' component. A compound component is one that consists of a directory containing your view file, plus any related files. The directory name must be the same as the component view file name. So to turn our simple blockquote component into a compound component, we will put it into a subdirectory called `blockquote` and add our related files. So, with the addition of a few extra files, our blockquote component might now look something like this:
180 |
181 | ```
182 | ├── components
183 | │ ├── _preview.hbs
184 | │ ├── blockquote
185 | │ │ ├── blockquote.config.yml
186 | │ │ ├── blockquote--fancy.hbs
187 | │ │ ├── blockquote.hbs
188 | │ │ ├── blockquote.scss
189 | │ │ ├── modal-quote.js
190 | │ │ ├── screenshot.png
191 | │ │ └── README.md
192 | ```
193 |
194 | `README.md` files, if present, will parsed and used by Fractal to generate notes about the component. Other files (which can be called anything you like) will be taken to be associated with this component. Web UI themes can then display these alongside the rendered views.
195 |
--------------------------------------------------------------------------------
/docs/guide/components/including-sub-components.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Including sub-components
3 | ---
4 |
5 | # Including Sub-components
6 |
7 | Often you will want to include one component within another component. For instance, you may have a 'button' component that you want to include as a sub-component of a 'search box' component (as well as potentially within a number of other components).
8 |
9 | Using the default Handlebars template engine, that might look something like this:
10 |
11 | ```handlebars
12 |
13 |
14 | ```
15 |
16 | ```handlebars
17 |
18 |
19 |
20 | {{> @button }}
21 |
22 | ```
23 |
24 | As you can see, the `search-box.hbs` component view file uses the standard [Handlebars partial include](http://handlebarsjs.com/#partials) syntax to include the button template, with one difference - instead of using a *path* to the template, it uses the [`@handle` syntax](../core-concepts/naming.html#referencing-other-items) to refer to the button component by its handle.
25 |
26 | It's important to note that the syntax for including one component's view template within another **will depend on which [template engine](../customisation/template-engines.html) you are using**. For instance, if you were using the [Nunjucks engine](https://github.com/frctl/fractal/tree/main/packages/nunjucks) you would instead use Nunjuck's `include` tag to include sub components. For example:
27 |
28 | ```html
29 |
30 |
31 | {% include '@child' %}
32 |
33 | ```
34 |
35 | ## Container Components via @partial-block
36 |
37 | Apart from naming the subcomponent you'd want to include directly, you can also use handlebar's built in `@partial-block` to be able to wrap components inside container components. This is useful for creating preview templates where you want to be able to view a component variation inside a container component.
38 |
39 | ```handlebars
40 |
41 |
42 | {{> @partial-block}}
43 |
44 | ```
45 |
46 | Then you can use it like so:
47 |
48 | ```handlebars
49 | {{#> container}}
50 | {{> anotherPartial}}
51 | {{/container}}
52 | ```
53 |
54 | Or even in a preview template:
55 |
56 | ```handlebars
57 | {{#> container}}
58 | {{ yield }}
59 | {{/container}}
60 | ```
61 |
62 | ## Providing context data to sub-components
63 |
64 | When you include a sub-component in the manner described above, it's important to note that you are effectively just including the contents sub-component's view file. **It will not automatically include any [context data](../core-concepts/context-data.html) that you may have defined for that sub-component.**
65 |
66 | To handle passing context data for your included sub-components, you have a number of options:
67 |
68 | * A) Use the [render helper](../core-concepts/view-templates.html#handlebars-helpers) to render the sub-component in-place, using its own context data.
69 | * B) Define a complete set of context data in the parent component's config file
70 | * C) Reference context data for sub-components using the '@handle' [static data reference syntax](../core-concepts/naming.html#referencing-other-items) from within the parent component's context data.
71 |
72 | Let's look at how each of these might work in turn.
73 |
74 | ### A) Using the `render` helper
75 |
76 | Both the default [Handlebars template engine](../core-concepts/view-templates.html#template-rendering) and the [Nunjucks engine](https://github.com/frctl/fractal/tree/main/packages/nunjucks#helpers) come with a `render` helper to use in your templates, instead of the standard partial/include syntax.
77 |
78 | Unlike the standard 'include' syntax, the `render` helper renders a sub-component in-place, using its own context data (unless overridden by data passed into it). This is a good solution if you want to **render a sub-component with its own context data**, AND you don't mind using a custom helper function to handle the rendering.
79 |
80 | ::: tip
81 | If you are planning on consuming your template files outside of Fractal, you may **not** want to use a custom helper if it is will not be supported in your target environment.
82 | :::
83 |
84 | An example might look like this:
85 |
86 | ```handlebars
87 |
88 |
89 | ```
90 |
91 | ```yaml
92 | # button.config.yml
93 | context:
94 | button:
95 | text: A Button
96 | ```
97 |
98 | ```handlebars
99 |
100 |
101 |
102 |
103 | {{ render '@button' }}
104 |
105 | ```
106 |
107 | ```yaml
108 | # search-box.config.yml
109 | context:
110 | label: Search
111 | ```
112 |
113 | ::: v-pre
114 | You can see in this case, we don't need to specify any context data for the `button` sub-component in the `search-box.config.yml` - instead the `{{ render }}` helper will automatically render the `button` using the context data defined in its own `button.config.yml`.
115 | :::
116 |
117 | You can also override all or a just a sub-set of the sub-component's default context data - see the [Handlebars helpers](../core-concepts/view-templates.html#handlebars-helpers) or the [Nunjucks helpers](https://github.com/frctl/fractal/tree/main/packages/nunjucks) documentation for more info.
118 |
119 | ### B) Define all context data in the parent component's config
120 |
121 | This is a good approach for when you want to render an instance of the sub-component that should use a **different set of context data** to that which is provided in the sub-component's config file.
122 |
123 | For example, you may want to render a 'prose' component on its own with a set of Lorem Ipsum default content, but when pulled into a 'homepage' component you may want to override that with page-specific content.
124 |
125 | Using this method, our example would look like this:
126 |
127 | ```handlebars
128 |
129 |
130 | ```
131 |
132 | ```yaml
133 | # button.config.yml
134 | context:
135 | button:
136 | text: A Button
137 | ```
138 |
139 | ```handlebars
140 |
141 |
142 |
143 |
144 | {{> @button }}
145 |
146 | ```
147 |
148 | ```yaml
149 | # search-box.config.yml
150 | context:
151 | label: Search
152 | button:
153 | text: Go!
154 | ```
155 | You can see that in this case, the parent (`search-box`) component is providing a whole new set of context data, including the `button` object with its `text` property. The rendered output of both of these components would look like:
156 |
157 | ```html
158 |
159 |
160 | ```
161 |
162 | ```html
163 |
164 |
165 |
166 |
167 |
168 |
169 | ```
170 |
171 | So in this case the parent component is responsible for defining the context data used by both itself *and* and data needed by any sub-components.
172 |
173 | ### C) Use context data '@handle' references
174 |
175 | If you *don't* want to specify new data for all the sub-components in the parent's configuration file (and you don't want to use the `render` helper) you can use the '@handle' [static data reference syntax](../core-concepts/naming.html#referencing-other-items) to dynamically pull context from the sub-component's configuration in to the parent component's context.
176 |
177 | If we re-work the example above to use this technique it would look like this:
178 |
179 | ```handlebars
180 |
181 |
182 | ```
183 |
184 | ```yaml
185 | # button.config.yml
186 | context:
187 | button:
188 | text: A Button
189 | ```
190 |
191 | ```handlebars
192 |
193 |
194 |
195 |
196 | {{> @button }}
197 |
198 | ```
199 |
200 | ```yaml
201 | # search-box.config.yml
202 | context:
203 | label: Search
204 | button: "@button"
205 | ```
206 |
207 | The last line in the `search-box.config.yml` file (`button: "@button"`) ensures that the `button` context data property will be set to the value of the context data object defined in the button component; this is a reference that is resolved when the parent component is rendered.
208 |
209 | In this case, when rendered the components will look like:
210 |
211 | ```html
212 |
213 |
214 | ```
215 |
216 | ```html
217 |
218 |
219 |
220 |
221 |
222 |
223 | ```
224 |
225 | You can see that in the `@search-box` component the button text is now the same as the text defined in the `button.config.yml` file.
226 |
227 | See the documentation on [referencing other component\'s data](../core-concepts/context-data.html#data-references) for more information on using this technique.
228 |
229 | ### Fully rendering a sub-component
230 |
231 | If you're creating templates for a rendering system that uses bottom-up rendering, you may need to replace a variable with the complete markup from a sub-component.
232 | You can reference a component in your context and prefix it with `@@` to do this.
233 |
234 | For example, if you wanted to write templates for Drupal's local menu tasks -
235 |
236 | ```twig
237 |
238 |
255 | {% for tab in primary %}
256 | {{ tab }}
257 | {% endfor %}
258 |
259 | ```
260 |
261 | ```yaml
262 | # menu-local-tasks.config.yml
263 | context:
264 | primary:
265 | - @@menu-local-task
266 | - @@menu-local-task--active
267 | ```
268 |
--------------------------------------------------------------------------------
/docs/guide/components/notes.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Notes
3 | ---
4 |
5 | # Notes
6 |
7 | It's often very important to be able to clearly document the individual components in a system. You might want to include rationale about a component's structure, add notes on how and where it can be used or include any other useful information for the people who may be using the component library.
8 |
9 | Whilst Fractal lets you create rich standalone [documentation pages](../documentation/), often it makes more sense for individual components' documentation to live alongside the component itself. There are a few ways you can do this in Fractal:
10 |
11 | ## The README.md file
12 |
13 | [Components](../components/#components) and [variants](../component/#variants) can include notes in a markdown file (filename is case-insensitive), for example: `README.md`, `readme.md`, `.readme.md`, or `--.readme.md` file beside the component template file:
14 |
15 | ```
16 | ├── components
17 | │ ├── blockquote
18 | │ │ ├── blockquote.hbs
19 | │ │ └── README.md # or readme.md
20 | | ├── button.hbs
21 | | ├── button.readme.md
22 | | ├── button--primary.hbs
23 | | ├── button--primary.readme.md
24 | ```
25 |
26 | As noted above, for compound component `blockquote`, its `notes` can still be written in a `README.md` file.
27 |
28 | If present, the contents of the README file will be run through the **full Fractal documentation parser** before being displayed to the user in places such as the [web UI](../web/). That means that the file will be rendered with the documentation template engine (Handlebars by default) before being passed through a Markdown parser.
29 |
30 | This means you can do almost anything that you can do in standard documentation pages in your component-specific documentation, including creating ['dynamic' documentation](../documentation/dynamic-docs.html) that is tied tightly to the component's templates or context data.
31 |
32 | ::: warning
33 | Fractal does not support the use of YAML front-matter in README.md files.
34 | :::
35 |
36 | ## Notes in config files
37 |
38 | If you do not want to include a README.md file, you can also specify component notes in a configuration file using the `notes` property:
39 |
40 | ```js
41 | // my-component.config.json
42 | {
43 | "notes": "These are some **notes** about the component"
44 | }
45 | ```
46 |
47 | Notes created in this format will also be run through the template engine and Markdown parser before display.
48 |
--------------------------------------------------------------------------------
/docs/guide/components/preview-layouts.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Preview layouts
3 | ---
4 |
5 | # Preview Layouts
6 |
7 | By default, when Fractal renders a component, it does so without wrapping it in any 'page' structure markup.
8 |
9 | That means that it is effectively an HTML *fragment*, as opposed to an HTML *page*. As a result, your components will appear unstyled; Fractal **does not** automatically insert any styles or behaviour into the rendered markup.
10 |
11 | In order to faithfully render a component in the same way as it will look in your live site, Fractal supports the use of **preview layouts**. These are used when rendering component previews, and allow you to 'wrap' your component in some page markup so you can do things like link to your stylesheets, JavaScript files and so on, just as you would in your site proper.
12 |
13 | ## Creating a preview layout
14 |
15 | Preview layouts are just another component, and so must reside in your component directory. Like any other components, preview layouts can be hidden by prefixing their name with an underscore if you don't want them to show up in listings or navigation.
16 |
17 | For example, we could create a preview layout called `_preview.hbs` in the root our components directory:
18 |
19 | ```
20 | ├── components
21 | │ └── _preview.hbs
22 | ```
23 |
24 | The contents of that file might look something like this:
25 |
26 | ```handlebars
27 |
28 |
29 |
30 |
31 |
32 | Preview Layout
33 |
34 |
35 |
36 | {{{ yield }}}
37 |
38 |
39 |
40 | ```
41 |
42 | ::: v-pre
43 | Note the `{{{ yield }}}` placeholder. That is where the rendered component will be included into the final generated markup.
44 | :::
45 |
46 | ::: tip
47 | The triple `{{{` mustache tags around the `yield` placeholder are required so that handlebars does not automatically escape the rendered HTML of the component - if you are using a different templating language then you may need a different syntax to prevent the template engine from escaping the output.
48 | :::
49 |
50 | ::: v-pre
51 | We can also see that the layout is including a stylesheet. The `href` attribute value of the stylesheet `link` element is being generated by a Handlebars helper - `{{ path '/example.css' }}`. For details on this and how to link to static assets such as CSS, JavaScript files and images from your preview layouts and view templates, see the [documentation on static assets](../web/#static-assets).
52 | :::
53 |
54 | You can put as much or as little as you want into your preview layouts, but it's recommended that they match up as much as possible to the 'real' template that your components will be rendered in when used in your site.
55 |
56 | ## Specifying a preview layout for a component
57 |
58 | You can specify a default preview layout to use on a global basis or on a [component-by-component basis](./configuration-reference.html#preview) (allowing different layouts for different use-cases).
59 |
60 | You can also take advantage of the [configuration cascade](../core-concepts/configuration-files.html#configuration-inheritance) and specify preview layouts on a per-collection basis as the default for all components in that collection.
61 |
62 | In all cases, the preview layout must be referenced by the **handle** of the layout component.
63 |
64 | ### Global (default) preview layout
65 |
66 | You can set the default preview layout on your Fractal instance using the [@handle reference](../core-concepts/naming.html#referencing-other-items) for the chosen layout.
67 |
68 | ```js
69 | fractal.components.set('default.preview', '@preview');
70 | ```
71 |
72 | ### In a parent collection's configuration file
73 |
74 | All components within this collection will have this set as their default preview layout unless the specifically override it.
75 |
76 | ```js
77 | // patterns.config.json
78 | {
79 | "preview": "@preview"
80 | }
81 | ```
82 | ### In a component's configuration file
83 |
84 | Setting it directly in a component's config file will override any defaults set further upstream.
85 |
86 | ```js
87 | // component.config.json
88 | {
89 | "preview": "@preview"
90 | }
91 | ```
92 |
93 | ## Context in preview layouts
94 |
95 | Preview layouts are just components and can have their own configuration files associated with them, just like any other components. That means you can specify context data for the layout in the configuration file, and you will be able to access it from within the layout.
96 |
97 | You **will not** be able to access the layout's context data from within the component that is being rendered. The component is not *included* as a partial in the layout, but rather rendered first and then passed in as a property on the layout's context data.
98 |
99 | ### The `_target` property
100 |
101 | Preview layouts, when rendered as a layout and not as a component on their own, will have access to a special context property called `_target`. This is a JSON representation of whichever component or variant is being rendered within the layout.
102 |
103 | Having access to this means that you can do things like dynamically set the page title of your layout based on the component being rendered. For instance, in your layout template you could do:
104 |
105 | ```handlebars
106 |
107 | {{ _target.label }} | My Component Library
108 |
109 | ```
110 |
111 | Your page title would then match the component being rendered.
112 |
113 | ## Preview rendering details
114 |
115 | It may be useful to understand the exact rendering order when a preview layout is used. The rendering works as follows:
116 |
117 | 1. The component view is rendered, using its own set of context data.
118 | 2. The rendered output is assigned to a special property, `yield`, which is attached to the preview layout's context data.
119 | 3. A JSON representation of the component being rendered is assigned to the `_target` property of the layout's context data.
120 | 4. The layout view file is rendered using its own preview context data, complete with the additional `yield` and `_target` properties.
121 |
--------------------------------------------------------------------------------
/docs/guide/components/variants.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Variants
3 | ---
4 |
5 | # Variants
6 |
7 | Variants are useful when you have one component that has a **multiple different possible implementations**. For instance, you may have a 'notification banner' component. This might have a default style but also a number of variations - for example a 'warning' banner and 'success' banner. These could be implemented as separate components but often it's easier and more semantic to create them as variants of the default banner component.
8 |
9 | A component can have as many variants as you like. Behind the scenes, *every* component has at least one variant - when you are previewing or rendering a component you are actually seeing its 'default' variant, even if you have not explicitly defined one.
10 |
11 | Variants will typically use the default view template for the component they belong to; the variation comes from the ability to define a different set of [context data](../core-concepts/context-data.html) that will be used when rendering previews. However it is also possible to use a completely different view template if desired (which itself can include the main view template as a partial should you so wish).
12 |
13 | ## Creating variants
14 |
15 | There are a few ways to create variants of a component. They can be defined within the parent component's configuration file; they can be created by adding an additional view file within the directory that the main component view file resides; or they can be created using a combination of both methods.
16 |
17 | ### Defining variants in the component's config file
18 |
19 | Component [configuration files](../core-concepts/configuration-files.html) let you specify `variants` property. The value of this should be an array of variant definition objects. For example:
20 |
21 | ```js
22 | // notifications.config.json
23 | {
24 | "title": "Notification Banner",
25 | "variants": [
26 | {
27 | "name": "warning"
28 | },
29 | {
30 | "name": "success"
31 | }
32 | ]
33 | }
34 | ```
35 |
36 | ::: tip
37 | Every variant that is defined *must* have a value for the `name` property. **This is the only required property for a variant.**
38 | :::
39 |
40 | Variants inherit many properties set on the parent component, or indeed further up in the [configuration cascade](../core-concepts/configuration-files.html#configuration-inheritance), which means that you can set properties like `status` only once, on the parent component, and then just override them on a variant-by-variant basis if needed. The [component configuration reference](../components/configuration-reference.html) has full details on the properties you can set on your variants.
41 |
42 | The above example wouldn't give us anything very interesting, so let's look at how we could actually implement the notification banner example described in the overview section. Given a view template that looks like this:
43 |
44 | ```handlebars
45 |
46 |
50 | ```
51 |
52 | We can define the required variants in the component config file like this:
53 |
54 | ```js
55 | // notifications.config.json
56 | {
57 | "title": "Notification Banner",
58 | "status": "ready",
59 | "context": {
60 | "modifier": "default",
61 | "closeButtonText": "close",
62 | "message": "This is the default banner"
63 | },
64 | "variants": [
65 | {
66 | "name": "warning",
67 | "context": {
68 | "modifier": "alert",
69 | "message": "This is a warning banner"
70 | }
71 | },
72 | {
73 | "name": "success",
74 | "status": "prototype",
75 | "context": {
76 | "modifier": "success",
77 | "message": "This is a success banner"
78 | }
79 | }
80 | ]
81 | }
82 | ```
83 | This will give **three** variants; the default component variant, plus a `warning` and a `success` variant.
84 |
85 | In this example all of the variants will use the same view template, but will pass it different data when rendered as a preview. Because the default component configuration specifies a `closeButtonText` value in its context data, the variants do not need to - they only need to override the properties that need to be different for that particular variant.
86 |
87 | Similarly, by specifying a top-level `status` value, all variants will *inherit* that status unless explicitly specified, as the `success` variant does.
88 |
89 | ### Creating file-based variants
90 |
91 | If you want to create a variant that has different markup from the default component view, you can also create a variant by adding another view file into the same directory as the default component view. This needs to be named in the format `--.hbs` (or with the appropriate file extension for the template engine you are using).
92 |
93 | For instance, we could recreate the example above using files by creating the following file structure:
94 |
95 | ```
96 | ├── components
97 | │ └── notification
98 | │ │ ├── notification--success.hbs
99 | │ │ ├── notification--warning.hbs
100 | │ │ └── notification.hbs
101 | ```
102 |
103 | Each variant can then have its own markup, and by default will be rendered with whatever context data is defined in the parent component's configuration file (if any).
104 |
105 | ### Mixing configuration and file based variants
106 |
107 | It is also possible to mix the two approaches described above, which is useful when you want to define a variant with its own view file but which also has some additional configuration data associated with it.
108 |
109 | By defining a variant view file called `notification--success.hbs` you are actually defining the view template to be used for the `success` variant. If that variant is **not** defined in the components' config file then it is rendered with the default component context data and information. However if a variant with that name *is* defined in the component configuration, then that view will be used when rendering that component, and any configuration data (such as `label` etc) will be applied to that view.
110 |
111 | So by combining both examples above, each of the notification banner variants would have both their own markup *and* their own context data (and status, etc).
112 |
113 | ## The default variant
114 |
115 | Every component has a default variant. When you render a component, you are in fact rendering it's default variant, even if you have not explicitly created one.
116 |
117 | The 'default' variant is created implicitly from component configuration data. However if you want to manually override anything for the default variant you can also explicitly create a variant with the name `default` and set its properties there. For example, to change the navigation label from 'Default' to 'Base' you could do this:
118 |
119 | ```js
120 | // notifications.config.json
121 | {
122 | "title": "Notification Banner",
123 | "variants": [
124 | {
125 | "name": "default",
126 | "label": "Base"
127 | },
128 | // other variants...
129 | ]
130 | }
131 | ```
132 |
133 | If you _don't_ want to use the name 'default', you can specify the name of the variant to be used as the default variant by using the `default` property within the component's configuration. For example:
134 |
135 |
136 | ```js
137 | // notifications.config.json
138 | {
139 | "title": "Notification Banner",
140 | "default": "primary", // default will now be the variant with the name 'primary'
141 | "variants": [
142 | {
143 | // this is the 'default' variant
144 | "name": "primary",
145 | "label": "Primary"
146 | },
147 | {
148 | "name": "secondary",
149 | "label": "Secondary"
150 | },
151 | // other variants...
152 | ]
153 | }
154 | ```
155 |
156 | ### Default variants and context data
157 |
158 | Context data defined at the component level will cascade down to all the variants of that component. If you do not wish to have context data shared between variants, but _do_ wish to have context data available to the default variant, then simply skip defining a top-level context object and instead set it directly on the default component, like so:
159 |
160 | ```js
161 | // notifications.config.json
162 | {
163 | "title": "Notification Banner",
164 | "context": {}, // no shared context
165 | "variants": [
166 | {
167 | "name": "default",
168 | "label": "Base",
169 | "context": {
170 | // this context is only applied to the default variant
171 | "message": "This is a standard notification"
172 | }
173 | },
174 | // other variants...
175 | ]
176 | }
177 | ```
178 |
179 | ## Referencing variants
180 |
181 | Variants can be referenced using the component `@handle` syntax, suffixed with a double hyphen and the variant's name. So using the example above, you could reference the success variant via the handle `@notification--success`.
182 |
183 | ::: tip
184 | It's worth noting that if you include a variant as a partial within another component, and that variant *does not* have its own view template, the effect will be identical to including the component itself, as they will share the same template.
185 | :::
186 |
187 | ## Collated components
188 |
189 | Variants are generally exposed in UIs (such as the web UI) as individual items under the main component. In some cases you may want to render the component as a *collated component*, in which case it will instead appear as a single component with a preview that concatenates all the variant previews together into a single view.
190 |
191 | This can be useful for when you have many variations of a small component such as a button and want to preview them all together, rather than having to flick between previews of each one individually.
192 |
193 | To render a component in this way you need to set the `collated` property to `true` in the [component configuration file](../components/configuration-reference.html#component-properties).
194 |
--------------------------------------------------------------------------------
/docs/guide/core-concepts/configuration-files.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Configuration Files
3 | ---
4 |
5 | # Configuration Files
6 |
7 | Components, documentation pages and collections can all have their own (optional) configuration files associated with them.
8 |
9 | In order to be recognised, configuration files must:
10 |
11 | * Reside in the same directory as the item that they are configuring
12 | * Have a file name in the format `item-name.config.{js|json|yml}` - for example `button.config.json`, `patterns.config.js` or `changelog.config.yml`
13 |
14 | ## Available configuration options
15 |
16 | The available configuration options depend on the type of the item being configured. See the relevant configuration reference for details:
17 |
18 | * [Components](../components/configuration-reference.html)
19 | * [Pages](../documentation/configuration-reference.html)
20 | * [Collection](../collections/configuration-reference.html)
21 |
22 | ## Configuration file formats
23 |
24 | Configuration files can be formatted as [JSON](http://json.org/), [YAML](http://yaml.org/) or as a JavaScript file in the style of a CommonJS module that exports a configuration object.
25 |
26 | The latter is recommended as it offers a lot more flexibility, but you may want to choose JSON or YAML if you have a particular need to keep things simple and declarative.
27 |
28 | ### JavaScript module format
29 |
30 | Configuration files authored in this format must have a filename that looks like `item-name.config.js`.
31 |
32 | Using the JavaScript (CommonJS) module format for your configuration files is a little more involved than using JSON or YAML, but is a **lot more powerful** as it allows you to do things like dynamically generating component [context data](./context-data.html)
33 |
34 | The file itself should be in the format of a Node CommonJS-style module that exports a configuration object. If you don't know what that is, don't worry! Just make sure its contents look like this:
35 |
36 | ```js
37 | module.exports = {
38 | // config data here
39 | };
40 | ```
41 |
42 | For example, a component configuration file in this format might look like this:
43 |
44 | ```js
45 | module.exports = {
46 | title: "Sparkly Buttons",
47 | status: "prototype",
48 | context: {
49 | "button-text": "Click me!",
50 | "is-sparkly": true
51 | }
52 | };
53 | ```
54 |
55 | ::: tip
56 | As this is JavaScript and not JSON, the exported object doesn't need to conform to the JSON specification's strict syntax rules for things like double quoting keys and so on.
57 | :::
58 |
59 | Because it is just a JavaScript file, you can do things like use JavaScript to generate your context data for you, should you need to. Additionally, because it is imported as a NodeJS module, you can also `require` any third party NPM modules (or even your own module files) to help with any data-generation - including doing things like fetching data form external APIs.
60 |
61 | See the [context data documentation](./context-data.html) for more details on ways to make use of this powerful feature.
62 |
63 | ### JSON format
64 |
65 | Configuration files authored using JSON must have a filename that looks like `item-name.config.json`.
66 |
67 | A simple example of a JSON-formatted config file for a component might look like:
68 |
69 | ```json
70 | {
71 | "title": "Sparkly Buttons",
72 | "status": "prototype",
73 | "context": {
74 | "button-text": "Click me!",
75 | "is-sparkly": true
76 | }
77 | }
78 | ```
79 |
80 | ::: tip Note
81 | The file must be valid JSON, with double quoted property names and string values, and without any trailing commas, or it will throw an error when it is parsed.
82 | :::
83 |
84 | ### YAML format
85 |
86 | Configuration files authored using YAML must have a filename that looks like `item-name.config.yml`.
87 |
88 | A simple example of a YAML-formatted config file for a component might look like:
89 |
90 | ```yaml
91 | title: "Sparkly Buttons"
92 | status: "prototype"
93 | context:
94 | button-text: "Click me!"
95 | is-sparkly: true
96 | ```
97 |
98 | ## Configuration inheritance
99 |
100 | Some configuration items will have their values *inherited* from upstream collections or their default settings if the values are not set in the item's configuration file directly.
101 |
102 | This can also be thought of a *cascade* of configuration values from their default settings down through any nested collection configurations and into the item itself.
103 |
104 | Whilst this is a somewhat advanced concept, it can often be very useful to save having to set the same configuration values on multiple items. For example, if all components in a collection need to have their status set to `wip` then rather than having to set it on each individual component you can just set it in the collection's configuration file and it will cascade down to the components. You can then override it on selected components if necessary.
105 |
106 | Pages and components each have different properties that can be inherited - see their respective configuration docs for details.
107 |
108 | ### Properties with primitive values
109 |
110 | Properties with primitive (i.e. non-object) values, if specified on a downstream entity, will **override** upstream values. For instance, to figure out the value of the `status` property for a component, Fractal will do the following:
111 |
112 | 1. Check if it is set directly in the component's configuration file. If so, use that.
113 | 2. Otherwise, recursively work upwards to check any parent collections to see if any of them have a status set in its configuration. If one is found to have a `status` specified, stop and use that.
114 | 3. If no value for the `status` is found, use the default value (which may or may not have been overridden in a `fractal.config.js` file or similar).
115 |
116 | ### Properties with object and array values
117 |
118 | Properties with object or array values are treated slightly differently. Instead of overriding upstream values, they are **merged with them**.
119 |
120 | For example, if a collection has been assigned the tags `['sprint-1', 'dashboard']` and one of its child components has the tags `['dashboard', 'needs-review']` specified in its component configuration, then the resolved, **aggregate** tag list for the component will be `['dashboard', 'needs-review', 'sprint-1']`.
121 |
122 | Similarly, context data is inherited and merged from upstream sources. For example, the following example set of configuration data:
123 |
124 | ```js
125 | // in the fractal.config.js configuration file
126 | fractal.components.set('default.context', {
127 | 'background': 'sparkly'
128 | });
129 |
130 | // in an upstream collection config file, e.g. patterns.config.json
131 | {
132 | "context": {
133 | "special-sauce": true,
134 | "background": "stars"
135 | }
136 | }
137 |
138 | // in the component configuration file, e.g. button.config.json
139 | {
140 | "context": {
141 | "text": "Click here!"
142 | }
143 | }
144 | ```
145 | Would result in the resolved, aggregate context of the component looking like:
146 |
147 | ```js
148 | {
149 | "background": "stars",
150 | "special-sauce": true,
151 | "text": "Click here!"
152 | }
153 | ```
154 |
--------------------------------------------------------------------------------
/docs/guide/core-concepts/context-data.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Context Data
3 | ---
4 |
5 | # Context Data
6 |
7 | Context data is data that is made available to your [view templates](./configuration-files.html) when they are rendered.
8 |
9 | It is typically defined within a [configuration file](./configuration-files.html), although documentation pages can opt to define it in in a [YAML front-matter section](../documentation/#yaml-front-matter) instead if desired.
10 |
11 | Context data can consist of simple data types such strings, booleans, numbers, arrays and objects. It can also contain Promises (which will be resolved before context data is made available for use) and special 'static data references' that allow referencing of context data from other components or documentation pages.
12 |
13 | ## Defining & using context data
14 |
15 | To define context data for a component or documentation page you should to set a `context` object in the relevant configuration file:
16 |
17 | ```js
18 | // my-component.config.json
19 | {
20 | "context": {
21 | // context data goes here
22 | }
23 | }
24 | ```
25 |
26 | Any data set within this context object will then be made available to that item's [view template](./view-templates.html) as variables. For example:
27 |
28 | ```js
29 | // users.config.json
30 | {
31 | "context": {
32 | "title": "Our users",
33 | "users": [{
34 | "name": "Mickey Mouse",
35 | "email": "mickey@mouse.com"
36 | },{
37 | "name": "Daffy Duck",
38 | "email": "daffy@duck.com"
39 | }]
40 | }
41 | }
42 | ```
43 |
44 | ```handlebars
45 |
46 |
47 |
{{ title }}
48 |
49 | {{#each users}}
50 |
51 |
{{ name }}
52 |
{{ email }}
53 |
54 | {{/each}}
55 |
56 |
57 | ```
58 |
59 | ## Static data references
60 |
61 | Context data object also support the use of _data references_. These are special references, resolved at runtime, that allow you to 'point' to other item's context data.
62 |
63 | This is made possible using the `@handle` [reference syntax](./naming.html#referencing-other-items) in your context data definitions. For example, if we create a configuration file for a component called `list-items` that looks like this:
64 |
65 | ```yaml
66 | context:
67 | title: My favourite list items
68 | items:
69 | - one
70 | - two
71 | - three
72 | - four
73 | ```
74 | It is then possible to access the `list-items` component's context data in another component as follows:
75 |
76 | ```yaml
77 | context:
78 | list: '@list-items'
79 |
80 | # When resolved, the above context data (which will get passed to the template when rendered) will look as follows:
81 |
82 | context:
83 | list:
84 | title: My favourite list items
85 | items:
86 | - one
87 | - two
88 | - three
89 | - four
90 | ```
91 | You can also choose to access only part of another component's context data by using a dot-notation string after the main identifier handle:
92 |
93 | ```yaml
94 | context:
95 | list: '@list-items.items'
96 |
97 | # resolves to:
98 |
99 | context:
100 | list:
101 | - one
102 | - two
103 | - three
104 | - four
105 | ```
106 |
107 | ::: tip
108 | The reference syntax only applies to items of **the same type** - a component cannot access a documentation page's context data (or vice versa).
109 | :::
110 |
111 | ## Dynamic data
112 |
113 | Fractal provides the option [to use CommonJS-style modules](./configuration-files.html#javascript-module-format) to define configuration data for components and documentation pages. Whilst slightly more complex than using JSON or YAML as a data format, it has the advantage of letting you be able to use the full power of JavaScript to generate context data for your components.
114 |
115 | This can be handy if you want to provide data to your components from an API, or to use a library such as [Faker](https://github.com/marak/Faker.js) to generate placeholder data for your components.
116 |
117 | You can use any NodeJS functionality or NPM modules you like in your configuration data files, so the possibilities for generating dynamic data are effectively endless!
118 |
119 | ### Generating dynamic data with Faker
120 |
121 | To save us hard-coding lots of context data into our data file, we can use the excellent [faker.js](https://github.com/marak/Faker.js) library to generate a list of members for us.
122 |
123 | First you'll need to make sure you have installed Faker in your component library project - `npm install faker --save`.
124 |
125 | And now let's look at an example `member-list.config.js` file and see how we can use Faker to dynamically generate a list of members for us.
126 |
127 | ```js
128 | // member-list.config.js
129 | 'use strict';
130 |
131 | const faker = require('faker'); // require the faker module
132 | const memberCount = 10; // how many members we should generate data for
133 | const memberData = [];
134 |
135 | for (var i = 0; i < memberCount; i++) {
136 | memberData.push({
137 | name: faker.name.findName(), // generate a random name
138 | email: faker.internet.email() // generate a random email address
139 | });
140 | }
141 |
142 | module.exports = {
143 | context: {
144 | members: memberData // use our generated list of members as context data for our template.
145 | }
146 | };
147 | ```
148 |
149 | When our component is now rendered with this data, we will get a list of ten members, all with realistic names and email addresses. And if we want to generate 100 list items instead, all we have to do is update the value of the `memberCount` constant to 100.
150 |
151 | Obviously this is a simple example, but the principle can often be useful when you want to preview components with large amounts of data in them.
152 |
153 | ### Using data from an API
154 |
155 | If you already have an API for your site or application, and you want to preview your components using 'real' data (or indeed if you want to use content from any other APIs) then you can handle that in your component configuration files too.
156 |
157 | The key to this is that if any values in the context data are [Promises](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise), Fractal will first wait for those promises to be resolved before rendering the template using the context data. So we can use a Promise-based request module (such as [request-promise-native](https://github.com/request/request-promise-native)) to make API requests and then just pass the returned promise into our context data object.
158 |
159 | In the following example, we are going to make a request to our fictional members API endpoint, which returns a JSON-encoded list of members.
160 |
161 | ```js
162 | // member-list.config.js
163 | 'use strict';
164 |
165 | const request = require('request-promise-native'); // require the request-promise-native module
166 |
167 | // make the request to the API, returns a Promise
168 | const response = request({
169 | uri: 'http://www.mysite-api.com/members',
170 | json: true
171 | });
172 |
173 | // do some post-processing on the response to wrangle it into the correct format
174 | response.then(function (membersApiData) {
175 | const memberData = [];
176 | for (let member of membersApiData) {
177 | memberData.push({
178 | name: `${member.firstName} ${member.lastName}`,
179 | email: member.emailAddress
180 | });
181 | }
182 | return memberData;
183 | });
184 |
185 | module.exports = {
186 | context: {
187 | members: response // use the response as context data for our template.
188 | }
189 | };
190 | ```
191 |
192 | Now when the component is rendered, it will first make an API request to the endpoint and wait for the Promise (and its associated `then()` step) to be resolved before using the output to pass as context data to the template.
193 |
--------------------------------------------------------------------------------
/docs/guide/core-concepts/naming.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Naming & Referencing
3 | ---
4 |
5 | # Naming & Referencing
6 |
7 | Fractal is a flat-file system, and makes use of some simple file and folder naming conventions to help it parse the file system and generate the underlying data model.
8 |
9 | And whilst Fractal will automatically generate a lot of data about items based on their file and folder names, it is of course straightforward to override that generated data with bespoke data if required.
10 |
11 | One of the main _disadvantages_ of flat-file systems is that when one item references another via a path, moving any of those items inevitably results in those links breaking. So Fractal also supports a **reference** system, whereby items can use 'handles' instead of paths to link parts of the system together.
12 |
13 | ## Generated names & handles
14 |
15 | Unless told otherwise, Fractal will infer the **name** of a component or documentation page from its [view template ](./view-templates.html) **file name** (or the parent directory for ['compound' components](../components/#compound-components)).
16 |
17 | It will then use this name (plus some other information) to generate a **handle** for the item. Handles are what will be used to reference that item elsewhere around your project.
18 |
19 | ::: tip
20 | **Names** and **handles** are both 'slug' type strings, and will contain only lowercase, alphanumeric characters plus underscores and dashes.
21 | :::
22 |
23 | The name will also be used to generate a default **label** and a **title** for the item. Labels are the text that will be used when the item is referenced in any navigation (for example in the [web UI](../web/)) and the title value is the text that will be used anywhere else a human-readable name for the item is required.
24 |
25 | Let's look at a simple example of how this works in practice, assuming that we have a component with a view template called `blockquote-large.hbs`:
26 |
27 | ```
28 | ├── components
29 | │ └── blockquote-large.hbs
30 | ```
31 |
32 | * **name**: `blockquote-large`
33 | * **handle**: `blockquote-large`
34 | * **label**: `Blockquote Large`
35 | * **title**: `Blockquote Large`
36 |
37 | ## Uniqueness
38 |
39 | Fractal relies on all items of a particular 'type' having **a unique handle**. So no two components can have the same 'button' handle, for instance, but you _could_ have a component called 'button' **and** documentation page called 'button', if you liked.
40 |
41 | So in the following situation, Fractal would not 'see' the second `button` component:
42 |
43 | ```
44 | ├── components
45 | │ ├── standard
46 | │ │ └── button.hbs
47 | │ └── special
48 | │ └── button.hbs
49 | ```
50 |
51 | Luckily this problem is easy to fix! You can take one of two approaches:
52 |
53 | 1. Use a [collection prefix](#prefixes) to generate unique handles for the items within a collection
54 | 2. Set a [bespoke handle](#customising-names-and-handles) for the item in question within the item's configuration file.
55 |
56 | ## Ordering and hiding
57 |
58 | Fractal also supports the use of optional filename 'metadata' for _hiding_ and _ordering_ components and pages. **This metadata is ignored when generating the item's name and other properties.**
59 |
60 | Items can be ordered by prefixing file names with a **two digit number** (with leading zero, if required) **followed by a hyphen**. For example:
61 |
62 | ```
63 | ├── pages
64 | │ ├── 01-index.md
65 | │ ├── 02-changelog.md
66 | │ └── 03-naming-conventions.md
67 | ```
68 |
69 | Items can be hidden by **prefixing the filename by an underscore**:
70 |
71 | ```
72 | ├── components
73 | │ ├── _hidden-component.hbs
74 | │ └── article.hbs
75 | ```
76 |
77 | ::: tip Note
78 | Any hidden components or variants can still be referenced by other components, included in templates etc, but will not be included in any navigation.
79 | :::
80 |
81 | ## Prefixes
82 |
83 | If you have your components or docs organised into sub-folder [collections](../collections/) then you can include a collection [configuration file](./configuration-files.html) to specify properties that will apply to all the items within that collection.
84 |
85 | One of the available properties you can set on a collection is the `prefix` property. When you set a value for this property in a parent collection, all children of this collection will have handle's generated that take the format `[prefix]-[item-name]`, making them much more likely to be unique across your whole component library.
86 |
87 | Given the following setup:
88 |
89 | ```
90 | ├── components
91 | │ ├── standard
92 | │ │ └── button.hbs
93 | │ └── special
94 | │ ├── special.config.json
95 | │ ├── alert.hbs
96 | │ └── button.hbs
97 | ```
98 |
99 | ```js
100 | // special.config.json
101 | {
102 | "prefix": "sparkly"
103 | }
104 | ```
105 |
106 | The handles generated for the two components in the `special` collection would be `sparkly-alert` and `sparkly-button`.
107 |
108 | ## Customising names & handles
109 |
110 | You can also specify custom **names** and **handles** in an item's own configuration file to override the ones that would be auto-generated from the file name by Fractal.
111 |
112 | See the configuration reference documentation for [components](../components/configuration-reference.html) and [documentation pages](../documentation/configuration-reference.html) for full details of how to set custom names, handles, labels and titles.
113 |
114 | There are a few things to note when specifying bespoke names or handles for items:
115 |
116 | * **Handles** are generated from **names**, so customising a name **will also change** the item's generated handle (unless that too is overridden).
117 | * Changing the **name** of an item will _not_ prevent its **handle** from having any [prefix](#prefix) applied to it when it is generated. However if you specify a custom **handle** any parent collection prefixes **will be ignored** for that item.
118 |
119 | ## Referencing other items
120 |
121 | You can use an item's handle to reference it throughout your project, using the special `@[handle]` reference syntax.
122 |
123 | This syntax can be used in a number of places, including:
124 |
125 | * [Static data references](./context-data.html#static-data-references) in context data
126 | * Including [sub-component view templates](../components/including-sub-components.html) within parent templates
127 | * Specifying [preview layouts](../components/preview-layouts.html) in configuration data
128 |
129 | So for this example structure and data:
130 |
131 | ```
132 | ├── components
133 | │ └── banner.hbs
134 | │ ├── standard
135 | │ ├── button.config.json
136 | │ │ └── button.hbs
137 | │ └── special
138 | │ ├── special.config.json
139 | │ ├── alert.hbs
140 | │ └── button.hbs
141 | ```
142 |
143 | ```js
144 | // components/standard/button.config.json
145 | {
146 | "handle": "clickme"
147 | }
148 | ```
149 | ```js
150 | // components/special/special.config.json
151 | {
152 | "prefix": "sparkly"
153 | }
154 | ```
155 |
156 |
157 | The following references could be used:
158 |
159 | ```
160 | banner.hbs --> @banner
161 | standard/button.hbs` --> @clickme
162 | special/alert.hbs` --> @sparkly-alert
163 | special/button.hbs` --> @sparkly-button
164 | ```
165 |
166 | For example in a component view template, to include another component as a [sub-component](../components/including-sub-components.html):
167 |
168 | ```handlebars
169 |
170 |
171 |
Some banner text here
172 |
Click here if you like this! {{> @sparkly-button}}
173 |
174 | ```
175 |
--------------------------------------------------------------------------------
/docs/guide/core-concepts/statuses.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Statuses
3 | ---
4 |
5 | # Statuses
6 |
7 | [Components](../components/) and [documentation pages](../documentation/) can have statuses associated with them.
8 |
9 | Each status has a colour and a label that can be displayed in the [web UI](../web/) (and other places) to help people quickly understand the status of each component.
10 |
11 | Fractal defines some default statuses, but you are free to define your own to suit the needs of your project, or customise the colours and labels associated with these statuses.
12 |
13 | ## Default statuses
14 |
15 | A default status can be set globally for both components and documentation pages. If you wish to **disable** the default status then you can set the value to `null`. Items will then not have a status unless specified in their configuration (or in a parent collection's configuration).
16 |
17 | ### Components
18 |
19 | ```js
20 | fractal.components.set('default.status', 'wip');
21 | ```
22 |
23 | By default the available options are `ready`, `wip` and `prototype`.
24 |
25 |
26 | ### Documentation pages
27 |
28 | ```js
29 | fractal.docs.set('default.status', 'draft');
30 | ```
31 |
32 | By default the available options are `ready` and `draft`.
33 |
34 | ## Setting the status of an item
35 |
36 | You can specify a status for an item in its [configuration file](./configuration-files.md) (or in the YAML front-matter for documentation pages). For example:
37 |
38 | ```js
39 | // component.config.json
40 | {
41 | "status": "wip"
42 | }
43 | ```
44 |
45 | A status can also be defined for a [collection](../collections/); in this case the status will automatically be applied to all children unless specifically overridden on a case-by-case basis.
46 |
47 |
48 | ## Custom statuses
49 |
50 | Custom statuses sets can be defined for both components and documentation pages.
51 |
52 | ```js
53 | fractal.components.set('statuses', {
54 | /* status definitions here */
55 | });
56 |
57 | fractal.docs.set('statuses', {
58 | /* status definitions here */
59 | });
60 | ```
61 |
62 | The default statuses are defined as follows:
63 |
64 | ```js
65 | // components
66 | {
67 | prototype: {
68 | label: "Prototype",
69 | description: "Do not implement.",
70 | color: "#FF3333"
71 | },
72 | wip: {
73 | label: "WIP",
74 | description: "Work in progress. Implement with caution.",
75 | color: "#FF9233"
76 | },
77 | ready: {
78 | label: "Ready",
79 | description: "Ready to implement.",
80 | color: "#29CC29"
81 | }
82 | }
83 |
84 | // docs
85 | {
86 | draft: {
87 | label: 'Draft',
88 | description: 'Work in progress.',
89 | color: '#FF3333'
90 | },
91 | ready: {
92 | label: 'Ready',
93 | description: 'Ready for referencing.',
94 | color: '#29CC29'
95 | }
96 | }
97 | ```
98 |
99 | So as an example, if you only wanted two statuses for components, `doing` and `done`, you could use the following configuration:
100 |
101 | ```js
102 | // fractal.config.js
103 | fractal.components.set('statuses', {
104 | doing: {
105 | label: "Doing",
106 | description: "I'm doing it.",
107 | color: '#F00'
108 | },
109 | done: {
110 | label: "Done",
111 | description: "I'm done with this.",
112 | color: "green"
113 | },
114 | });
115 | ```
116 | You could then assign these new statuses to your components using the values `doing` and `done`.
117 |
118 | Alternatively, if you just want to change the label or colour on one of the existing statuses, you can target it specifically by its key:
119 |
120 | ```js
121 | fractal.components.set('statuses.prototype.color', 'pink');
122 | fractal.docs.set('statuses.ready.label', 'Good to go!');
123 | ```
124 |
--------------------------------------------------------------------------------
/docs/guide/customisation/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Customising Fractal
3 | ---
4 |
5 | # Customising Fractal
6 |
7 | Fractal offers a number of ways to extend its functionality.
8 |
9 | [Template engine adapters](../customisation/template-engines.html) let you use pretty much any JavaScript-based templating library instead of Handlebars, and [theme customisation](../customisation/web-themes.html) can give you a web UI completely tailored to the needs of your project.
10 |
11 | You can also use [custom CLI commands](../cli/custom-commands.html) to create command-line tasks that lean on the power of Fractal's API to better integrate your component library into your development workflow.
12 |
--------------------------------------------------------------------------------
/docs/guide/customisation/template-engines.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Template engines
3 | ---
4 |
5 | # Template engines
6 |
7 | By default, Fractal uses **Handlebars** to render [view templates](../core-concepts/view-templates.html) for both components and documentation pages.
8 | It's bundled with a number of built-in Fractal helpers, but you can also customise it to include your own custom helpers and/or partials if required.
9 |
10 | However, it's easy to use an alternate template engine (via the use of _adapters_) if you need a more bespoke solution for your project.
11 |
12 | ## Customising Handlebars
13 |
14 | See the [view templates documentation](../core-concepts/view-templates.html#using-handlebars) for details on how to customise the default Handlebars install to include your own helpers or partials.
15 |
16 |
17 | ## Loading template engines
18 |
19 | Template engines for components and documentation pages are loaded separately, using the `fractal.components.engine()` and `fractal.docs.engine()` methods respectively.
20 |
21 | If you don't need to customise the template engine adapter, you can just pass its package name into the `.engine()` method directly:
22 |
23 | ```js
24 | fractal.components.engine('@frctl/nunjucks'); // use Nunjucks for components
25 | fractal.docs.engine('@frctl/mustache'); // use Mustache for docs
26 | ```
27 |
28 | You will also likely want to change the file extension for the view template using the `ext` configuration option:
29 |
30 | ```js
31 | fractal.components.set('ext', '.nunj');
32 | fractal.docs.set('ext', '.html');
33 | ```
34 |
35 | ::: warning
36 | You must **install your chosen template adapter** package via `npm install` before you can use it with Fractal.
37 | :::
38 |
39 | ### Customising adapters
40 |
41 | If you wish to first customise the behaviour of the adapter (for instance to add helper methods or suchlike), the `.engine()` method will also accept a configured template engine adapter instance.
42 |
43 | The following is an example using the Fractal [Nunjucks adapter](https://github.com/frctl/fractal/tree/main/packages/nunjucks):
44 |
45 | ```js
46 | const nunjucks = require('@frctl/nunjucks')({
47 | filters: {
48 | shorten: function(str, count) {
49 | return str.slice(0, count || 5); // bespoke 'shorten' filter to use in view templates
50 | }
51 | }
52 | // ...other config properties here
53 | });
54 |
55 | fractal.components.engine(nunjucks); // use the configured Nunjucks instance for components
56 | fractal.components.set('ext', '.nunj'); // look for files with a .nunj file extension
57 | ```
58 |
59 | ::: warning
60 | Configuration details can vary between adapters, so you should refer to your chosen adapter's documentation for full configuration and setup details.
61 | :::
62 |
63 | ## Available adapters
64 |
65 | Currently there are specific 'official' adapters implemented for Handlebars, [Mustache](https://github.com/frctl/mustache), [Nunjucks](https://github.com/frctl/fractal/tree/main/packages/nunjucks) and [Twig](https://github.com/frctl/fractal/tree/main/packages/twig). However, if you want to use something else, there is also a [generic adapter](https://github.com/frctl/consolidate) that uses the Consolidate.js library to provide compatibility with 30+ other template engines.
66 |
67 | For full information on installing, using and customising individual template engine adapters, see the appropriate READMEs:
68 |
69 | * Handlebars adapter - see the [view templates](../core-concepts/view-templates.html) documentation
70 | * [Mustache adapter](https://github.com/frctl/mustache)
71 | * [Nunjucks adapter](https://github.com/frctl/fractal/tree/main/packages/nunjucks)
72 | * [Twig adapter](https://github.com/frctl/fractal/tree/main/packages/twig)
73 | * [Generic/consolidate adapter](https://github.com/frctl/consolidate)
74 |
--------------------------------------------------------------------------------
/docs/guide/customisation/web-themes.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Web UI themes
3 | ---
4 |
5 | # Web UI themes
6 |
7 | Themes are used to power the Fractal web UI. They are responsible not only for the visual look and feel of the UI, but also for what URLs are exposed and even what functionality is provided.
8 |
9 | The default theme, [Mandelbrot](../web/default-theme.html), showcases much of Fractal's functionality, and offers a range of customisation options to allow it to be tailored to the needs of individual projects.
10 |
11 | ## Configuring themes
12 |
13 | Themes will often expose a set of theme-specific configuration options, which can be applied when creating a new instance of a theme.
14 |
15 | Below is an example of passing custom configuration settings to Mandelbrot:
16 |
17 | ```js
18 | const mandelbrot = require('@frctl/mandelbrot');
19 |
20 | const myCustomisedTheme = mandelbrot({
21 | skin: "fuchsia",
22 | panels: ["html", "info", "resources"]
23 | });
24 |
25 | fractal.web.theme(myCustomisedTheme);
26 | ```
27 |
28 | See the Mandelbrot [configuration docs](../web/default-theme.html#customisation) for full details on available options, or the appropriate theme documentation/README for other themes.
29 |
30 | ::: warning
31 | You will need to `npm install` any theme that you want to customise before you can `require()` it in your project settings file.
32 | :::
33 |
34 | ## Template customisation
35 |
36 | Fractal themes use [Nunjucks](http://mozilla.github.io/nunjucks/) templates to generate their HTML. It is possible to override any templates supplied by a theme by specifying a custom template directory within your own Fractal project, and then including within it adjusted copies of the templates that you would like to override.
37 |
38 | Any templates within this directory **will be used in preference** to those of the same name within the theme's template directory.
39 |
40 | Specifing a template directory can be done in your project setup file using the `.addLoadPath()` method on the theme instance. For example, using Mandelbrot:
41 |
42 | ```js
43 | const myCustomisedTheme = require('@frctl/mandelbrot')({
44 | // theme config here
45 | });
46 |
47 | // specify a directory to hold the theme override templates
48 | myCustomisedTheme.addLoadPath(__dirname + '/theme-overrides');
49 |
50 | fractal.web.theme(myCustomisedTheme);
51 | ```
52 |
53 | Custom templates could then be placed into the `/theme-overrides` directory and will be used in preference of any named with the same relative path as those in the Mandelbrot `views` directory.
54 |
55 | ## Subclassing themes
56 |
57 | Often you will make tweaks to a theme that you want to apply to a number of projects. For instance, an agency may want all the component libraries that they build for clients to use the agency's own brand colours, and maybe some tweaks to the UI that they have made.
58 |
59 | Repeating these theme customisations for every project is clearly not an optimal solution, so instead it can often make more sense to _subclass_ the theme, make adjustments and then pull in the customised sub-theme as a dependency in other projects.
60 |
61 | ### An example sub-theme
62 |
63 | An example sub-theme folder structure, based on the default Mandelbrot theme with a few some UI tweaks, might look something like this:
64 |
65 | ```
66 | ├── assets
67 | │ └── tweaks.css
68 | ├── views
69 | │ └── partials
70 | │ └── header.nunj
71 | ├── index.js
72 | └── package.json
73 | ```
74 |
75 | Some things to note:
76 |
77 | * Theme customisation is be done in the `index.js` file, and this file should then `export` the customised theme instance (see example `index.js` file below).
78 | * The `views` directory is where templates used override the default theme templates live. In this case the partial `header.nunj` is being customised.
79 | * The `assets` directory contains static assets for the sub theme that can be linked to from the templates.
80 |
81 | ```js
82 | // index.js
83 | 'use strict';
84 |
85 | const mandelbrot = require('@frctl/mandelbrot');
86 |
87 | /*
88 | * Configure the theme
89 | */
90 | const subTheme = mandelbrot({
91 | skin: "fuchsia",
92 | styles: ['default', '/_subtheme/tweaks.css'] // link to the default stylesheet followed by a custom one
93 | });
94 |
95 | /*
96 | * Specify a template directory to override any view templates
97 | */
98 | subTheme.addLoadPath(__dirname + '/views');
99 |
100 | /*
101 | * Specify the static assets directory that contains the custom stylesheet.
102 | */
103 | subTheme.addStatic(__dirname + '/assets', '/_subtheme');
104 |
105 | /*
106 | * Export the customised theme instance so it can be used in Fractal projects
107 | */
108 | module.exports = subTheme;
109 | ```
110 |
111 | The sub-theme's `package.json` should include the parent theme as a dependency:
112 |
113 | ```js
114 | // package.json
115 | {
116 | "name": "my-subtheme",
117 | "version": "1.0.0",
118 | "description": "Fractal theme, based on Mandelbrot.",
119 | "main": "index.js",
120 | "dependencies": {
121 | "@frctl/mandelbrot": "^1.0.0"
122 | }
123 | }
124 |
125 | ```
126 |
127 | ### Publishing and using the theme
128 |
129 | Once you have created a sub-theme, you can [publish it as an NPM module](https://docs.npmjs.com/getting-started/publishing-npm-packages) or just push it up to a remote Git repository - for example on Github.com.
130 |
131 | You can then install the theme in any of your projects by installing it via NPM, using using the `npm install` command:
132 |
133 | ```
134 | npm install --save
135 | ```
136 |
137 | If you have not published the theme as a module but instead as a (for example) Github repo, you can still use the `npm install` command to install it [directly from your repository](http://www.zev23.com/2014/03/npm-install-from-github-or-bitbucket_13.html):
138 |
139 | ```
140 | npm install git+ssh://git@github.com//.git
141 | ```
142 |
143 | Then in the [setup file](../project-settings.html) for each of your projects you can `require` and use your subclassed theme:
144 |
145 | ```js
146 | // fractal.config.js
147 | 'use strict';
148 |
149 | const fractal = module.exports = require('@frctl/fractal').create();
150 | const mySubTheme = require('my-subtheme');
151 |
152 | // ... project setup and configuration
153 |
154 | fractal.web.theme(mySubTheme); // use the sub-classed theme
155 | ```
156 |
157 |
158 | ## Theme development from scratch
159 | ::: warning Coming soon...
160 | _Full theme development documentation is coming soon._
161 | :::
162 |
--------------------------------------------------------------------------------
/docs/guide/documentation/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | # Documentation Pages
6 |
7 | Fractal makes it easy to create documentation for your project. Documentation pages are written in [Github-flavoured Markdown](https://guides.github.com/features/mastering-markdown/) and support the use of YAML 'front-matter' for configuration, as well as configuration via standard [configuration files](../core-concepts/configuration-files.html).
8 |
9 | Additionally, if you need to generate more complex documentation, you can use a [template language](../core-concepts/view-templates.html) of your choosing (as for [components](../components/), the default is Handlebars) to help dynamically generate pages.
10 |
11 | Pages can be organised into as many folders and sub-folders as is necessary for your project, but must all reside in the documentation folder that you have configured in your [project settings](../project-settings.html).
12 |
13 | ## A simple page
14 |
15 | A very simple documentation page might look like this:
16 |
17 | ```markdown
18 | This is some documentation for the project. Still to do:
19 |
20 | * Finish the docs
21 | * Write tests
22 | * Make the tea
23 | ```
24 | Fractal will then take that and turn it into HTML ready for display:
25 |
26 | ```html
27 |
This is some documentation for the project. Still to do:
28 |
29 |
Finish the docs
30 |
Write tests
31 |
Make the tea
32 |
33 | ```
34 | If there is no configuration data available (see below) then Fractal will generate metadata (such the title of the page) based on the file name.
35 |
36 | ## YAML front-matter
37 |
38 | YAML 'front-matter' is a way of specifying configuration data at the top of a markdown file. It is a block of YAML that is fenced-off from the rest of the document via triple hyphen (`---`) separators. For example:
39 |
40 | ```yaml
41 | ---
42 | title: Change Log
43 | ---
44 | This is the body of the page
45 | ```
46 |
47 | In this case we are specifying that we want the title of the page (used in the web UI and other places) to be 'Change Log'. To see a full list of available configuration items, check out the [documentation configuration reference](../documentation/configuration-reference.html).
48 |
49 | If you don't want to use YAML front matter, you can also use a [separate configuration file](../core-concepts/configuration-files.html) in the same way as you would for a component.
50 |
51 | ## Using data in page templates
52 |
53 | Because pages are rendered using Handlebars (or another [template engine](../customisation/template-engines.html) of your choosing) before being run through the Markdown processor, you can easily dynamically generate sections of pages.
54 |
55 | As for components, any [context data](../core-concepts/context-data.html) that you wish to have access to in the page must be specified under the `context` property. You can then use Handlebars to generate content based on that data.
56 |
57 | For instance, if you are using YAML front matter, you could re-create the example at the start of this page as follows:
58 |
59 | ```handlebars
60 | ---
61 | title: Project Overview
62 | context:
63 | items:
64 | - Finish the docs
65 | - Write tests
66 | - Make the tea
67 | ---
68 | This is some documentation for the project. Still to do:
69 |
70 | {{#each items}}
71 | * {{ this }}
72 | {{/each}}
73 | ```
74 |
75 | ::: tip
76 | It's important to note that the template engine rendering happens **before** the Markdown parsing, so you are free to use it to generate Markdown or HTML (which is ignored by Markdown parsers).
77 | :::
78 |
79 | ### Accessing page metadata
80 |
81 | Pages only have direct access to data specified within the `context` object. If you need to access information about the page itself (such as the `title`) you have to use the special `_self` variable, as follows:
82 |
83 | ```handlebars
84 | {{ _self.title }}
85 | ```
86 |
87 | This is to prevent page configuration data clashing with context data intended to be used when rendering the page.
88 |
89 | Note that the `_self` variable is actually a JSON representation of the page object itself, and not just a regurgitation of configuration data (i.e. `title` will have a value whether or not it is overridden in the configuration, as Fractal generates one for every page).
90 |
91 | ## Ordering pages
92 |
93 | Pages can be ordered by prefixing file names with a **two digit number** (with leading zero, if required) **followed by a hyphen**. For example:
94 |
95 | ```
96 | ├── pages
97 | │ ├── 01-index.md
98 | │ ├── 02-changelog.md
99 | │ └── 03-naming-conventions.md
100 | ```
101 |
102 | Order prefixes are ignored when auto-generating page titles.
103 |
104 | Alternatively, you can use the `order` property in the page's configuration file to specify an order without amending the filename.
105 |
106 | ## Hiding pages
107 |
108 | Pages can be hidden from listings and navigation in two ways. You can either specify `hidden: true` in the pages's configuration file or you can prefix the page's filename with an underscore. So in the following example, the `changelog` page would not show up in any navigation:
109 |
110 | ```
111 | ├── pages
112 | │ ├── _changelog.md
113 | │ ├── index.md
114 | │ └── naming-conventions.md
115 | ```
116 |
117 | ::: tip
118 | You can also combine *ordering* and *hiding* by constructing a filename such as `_01-changelog.md`.
119 | :::
120 |
121 | ## Escaping Handlebars expressions
122 |
123 | Sometimes you may want to show a piece of code that itself contains a Handlebars expression, without that expression being parsed out at the rendering step. To do this you can prefix the expression with a backslash:
124 |
125 | ```handlebars
126 | \{{ foo }}
127 | ```
128 |
129 | This will prevent the Handlebars template engine from attempting to render that variable and will instead just keep it as a string.
130 |
--------------------------------------------------------------------------------
/docs/guide/documentation/configuration-reference.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Configuration reference
3 | ---
4 |
5 | # Configuring documentation pages
6 |
7 | There are a number of global configuration options you can set to determine how Fractal handles documentation pages.
8 |
9 | Additionally, documentation pages and [collections](../collections/) can have their own (optional) configuration files associated with them; or if you prefer pages can specify their configuration in a [YAML front-matter section](../documentation/#yaml-front-matter) within the page template itself. See the [documentation overview](../documentation/) for more information.
10 |
11 | ## Global configuration options
12 |
13 | These options can be set on your Fractal instance using the [`fractal.docs.set()`](../../api/endpoints/fractal-docs.html#set-path-value) method. See the [project settings](../project-settings.html) documentation for more details.
14 |
15 | ### default.context
16 |
17 | Global [context data](../core-concepts/context-data.html) that will be made available to all pages.
18 |
19 | ```js
20 | fractal.docs.set('default.context', {
21 | 'site-name': 'FooCorp'
22 | });
23 | ```
24 |
25 | ### default.prefix
26 |
27 | Global prefix to apply to all generated [handles](../core-concepts/naming.html#referencing-other-items) unless overridden in a collection or page configuration file.
28 |
29 | ```js
30 | fractal.docs.set('default.prefix', 'foobar'); // default is null
31 | ```
32 |
33 | ### default.status
34 |
35 | The status to apply to all pages unless overridden in a collection or page configuration file.
36 |
37 | ```js
38 | fractal.docs.set('default.status', 'wip'); // default is null
39 | ```
40 |
41 | ### ext
42 |
43 | The file extension that will be used for all documentation [view templates](../core-concepts/view-templates.html). Note that this must include the leading `.`
44 |
45 | ```js
46 | fractal.docs.set('ext', '.html'); // default is '.md'
47 | ```
48 |
49 | ### indexLabel
50 |
51 | The default label to be used for index pages.
52 |
53 | ```js
54 | fractal.docs.set('indexLabel', 'Listing'); // default is 'Overview'
55 | ```
56 |
57 | ### label
58 |
59 | How the collection of documentation pages will be referenced in any navigation.
60 |
61 | ```js
62 | fractal.docs.set('label', 'Pages'); // default is 'Documentation'
63 | ```
64 |
65 | ### markdown
66 |
67 | Whether to use Markdown to parse the contents of documentation pages.
68 |
69 | ```js
70 | fractal.docs.set('markdown', false); // defaults to true
71 | ```
72 |
73 | You can also toggle on or off other more fine-grained settings to customise the details of the Markdown parsing:
74 |
75 | ```js
76 | fractal.docs.set('markdown.smartypants', false);
77 | ```
78 |
79 | The default values are:
80 |
81 | ```js
82 | {
83 | gfm: true,
84 | tables: true,
85 | breaks: false,
86 | pedantic: false,
87 | sanitize: false,
88 | smartLists: true,
89 | smartypants: true
90 | }
91 | ```
92 |
93 | See the [Marked markdown parser documentation](https://github.com/chjj/marked#options-1) for details on what each option does.
94 |
95 | ### path
96 |
97 | The path to the directory where your documentation pages live.
98 |
99 | ```js
100 | fractal.docs.set('path', __dirname + '/src/docs');
101 | ```
102 |
103 |
104 |
105 | ### statuses
106 |
107 | The set of available statuses that can be assigned to pages. See the [statuses documentation](../core-concepts/statuses.html) for details of the default values and how to override them as required.
108 |
109 | ```js
110 | fractal.docs.set('statuses', {
111 | doing: {
112 | label: "Doing",
113 | description: "I'm doing it.",
114 | color: '#F00'
115 | },
116 | done: {
117 | label: "Done",
118 | description: "I'm done with this.",
119 | color: "green"
120 | }
121 | });
122 | ```
123 |
124 | ### title
125 |
126 | How the collection of documentation pages will be referenced in any titles.
127 |
128 | ```js
129 | fractal.docs.set('title', 'Pages'); // default is 'Documentation'
130 | ```
131 |
132 | ## Page properties
133 |
134 | These are properties that can be specified in an individual page's YAML front matter section _or_ in a configuration file for that page.
135 |
136 | ### context
137 |
138 | Data to pass to the page when rendering it.
139 |
140 | `context` is an **inheritable property**. Any context data set on the page will be *merged* with any context data set upstream in the [configuration cascade](../core-concepts/configuration-files.html#configuration-inheritance).
141 |
142 | ```yaml
143 | context:
144 | colors: ['red','pink','blue']
145 | ```
146 |
147 | ### handle
148 |
149 | Override the generated handle. Note that this will also have the side effect of preventing any [prefixes](#prefix) set in upstream collections being applied to the handle.
150 |
151 | ```yaml
152 | handle: my-great-page
153 | ```
154 |
155 | ### hidden
156 |
157 | Specifies whether the page is hidden (i.e. does not show up in listings or navigation) or not. Overrides the inferred value from an underscore-prefixed file name if set.
158 |
159 | ```yaml
160 | hidden: true
161 | ```
162 |
163 | ### label
164 |
165 | The label is typically displayed in any UI navigation items that refer to the page. Defaults to a title-cased version of the page file name if not specified.
166 |
167 | ```yaml
168 | label: 'Naming Conventions'
169 | ```
170 |
171 | ### order
172 |
173 | An integer order value, used when sorting pages. Overrides any order value set as a property of the filename if set.
174 |
175 | ```yaml
176 | order: 4
177 | ```
178 |
179 | ### title
180 |
181 | The title of a page. Defaults to the same as the `label` if not specified.
182 |
183 | ```yaml
184 | title: 'Amazing Mega Buttons'
185 | ```
186 |
187 | ## Collection properties
188 |
189 | Collections can specify properties that should be applied to all child pages of that collection via [configuration inheritance](../core-concepts/configuration-files.html#configuration-inheritance). See the [collections](../collections/) for more details on how to work with collections, and for details on available non-inheritable properties like `label` and `title`.
190 |
191 | The following properties can be set on page collections and will affect the pages within them:
192 |
193 | ### context
194 |
195 | Context data to be made available to (and merged into) all child pages within the collection.
196 |
197 | ```yaml
198 | context:
199 | colors: ['red','pink','blue']
200 | ```
201 |
202 | ### prefix
203 |
204 | A string to be prefixed on to the generated [handles](../core-concepts/naming.html#referencing-other-items) of all pages in that collection.
205 |
206 | ```yaml
207 | prefix: 'api'
208 | ```
209 | Given the prefix above, a page with the name of `logging` that lives within this collection will have the handle `@api-logging`.
210 |
211 | ### status
212 |
213 | The default status for all pages within the collection.
214 |
215 | ```yaml
216 | status: 'wip'
217 | ```
218 |
--------------------------------------------------------------------------------
/docs/guide/documentation/dynamic-docs.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Dynamic Documentation
3 | ---
4 |
5 | # Dynamic docs
6 |
7 | Because documentation pages are [views](../core-concepts/view-templates.html) that are run through a template engine, it is possible to dynamically embed information about your components into your documentation.
8 |
9 | This means that you can have documentation describing your components that stays up-to-date when aspects of your components change.
10 |
11 | ## Using bundled helpers
12 |
13 | You can use the [Handlebars helpers](../core-concepts/view-templates.html#handlebars-helpers) that ship with Fractal to embed the view template or context data for a component into your documentation. For example, if you were documenting a `button` component, you might have documentation that looks like this:
14 |
15 | ````markdown
16 | ## Button component
17 |
18 | The button component can be included within other components like this:
19 |
20 | ```
21 | \{{> @button }}
22 | ```
23 |
24 | This template for this component looks like this:
25 |
26 | ```
27 | {{view '@button'}}
28 | ```
29 |
30 | and it therefore expects a set of data to render it that is in the following format:
31 |
32 | ```
33 | {{context '@button'}}
34 | ```
35 | ````
36 |
37 | ::: v-pre
38 | When rendered, the `{{view '@button'}}` and `{{context '@button'}}` expressions would be evaluated, and the _actual_ view template code and sample context data would be rendered in place.
39 | :::
40 |
41 | Later on, if the `button` component template or context data is updated, then the documentation will also be automatically updated to match the changes, so it will never go out of date.
42 |
43 | ## Using the API
44 |
45 | It's possible to take this one step further using [Fractal\'s API](../../api/) in combination with creating your own helpers.
46 |
47 | When you set up your project, you can [customise the Handlebars engine](../core-concepts/view-templates.html#customising-handlebars) to add in your own helpers. These helpers can use Fractal API methods to provide you access to whatever data you need about your component library.
48 |
49 | For instance, if you wanted to create a Handlebars [block helper](http://handlebarsjs.com/block_helpers.html) that iterated over all of the available components in your project to create a list, you could use something like the following:
50 |
51 | ```js
52 | const hbs = require('@frctl/handlebars')({
53 | helpers: {
54 | componentList: function() {
55 | let ret = "
";
56 | const options = Array.from(arguments).pop();
57 | for (let component of fractal.components.flatten()) {
58 | ret = ret + "
" + options.fn(component.toJSON()) + "
";
59 | }
60 | return ret + "
";
61 | }
62 | }
63 | });
64 |
65 | fractal.docs.engine(hbs);
66 | ```
67 |
68 | You could then use this in your documentation pages to iterate over your components, for example to create a list of direct links to the component preview pages:
69 |
70 | ```markdown
71 | ## Component preview links:
72 |
73 | {{#componentList}}
74 | {{ this.title }}
75 | {{/componentList}}
76 | ```
77 |
78 | Which would output something like the following (depending on your components, obviously!):
79 |
80 | ```html
81 |
87 | ```
88 |
89 | See the [API documentation](../../api/) for details on how to access data about your component library programatically.
90 |
--------------------------------------------------------------------------------
/docs/guide/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting Started
3 | ---
4 |
5 | # Getting Started
6 |
7 | This guide outlines two ways of creating a new Fractal project. The end result is similar but the first one uses the Fractal CLI `new` command to generate the project structure for you, whilst the second goes through in a little more detail some of the steps involved.
8 |
9 | Both assume you have installed the Fractal CLI tool globally as described in the [installation guide](./installation.md).
10 |
11 | ## The TL;DR method
12 |
13 | 1. Open up your terminal in a folder where you would like your new project to be created.
14 | 2. Run the command `fractal new `, replacing `` with the name of the folder you want be created for your project. For instance, `fractal new example-project`
15 | 3. Answer the questions that you are prompted with.
16 | 4. Once the initial structure has been set up and the dependencies have been downloaded, `cd` into your new project folder - `cd example-project`
17 | 5. Start up the development server: `fractal start --sync`
18 | 6. Browse to the 'Local URL' displayed in your terminal to view your component library.
19 |
20 | ## The “from scratch” method
21 |
22 | The following steps will describe how to create a basic Fractal project from scratch.
23 |
24 | It assumes that you have already created a new, empty directory for your project and have installed Fractal as a dependency in your project (as well as the global CLI tool). If not then first check out the [installation guide](./installation.md) for instructions.
25 |
26 | ### 1. Set up your project structure
27 |
28 | The first thing to do is to create directories for your components and for your documentation pages. These can be called whatever you like and can live anywhere in your project directory. In this example they will be called `components` and `docs` and will reside within a parent `src` directory.
29 |
30 | So the project directory now looks like this:
31 |
32 | ```
33 | ├── src
34 | │ ├── components
35 | │ └── docs
36 | └── package.json
37 | ```
38 |
39 | You can of course put anything else you like into your project directory - build files, READMEs, other app code, whatever you like. Fractal will just ignore anything it doesn't recognise.
40 |
41 | ### 2. Create and configure a Fractal instance
42 |
43 | You now need to create a new instance of Fractal, and set a few configuration options to tell it about the structure of your project and other information.
44 |
45 | The convention is to do this in a file named `fractal.config.js` in the root of your project directory:
46 |
47 | ::: tip
48 | Note that previously the config file was called `fractal.js` by default. This changed in v1.3.0.
49 | :::
50 |
51 | ```
52 | ├── src
53 | │ ├── components
54 | │ └── docs
55 | ├── fractal.config.js
56 | └── package.json
57 | ```
58 |
59 | A very simple `fractal.config.js` file should look something like this:
60 |
61 | ```javascript
62 | 'use strict';
63 |
64 | /* Create a new Fractal instance and export it for use elsewhere if required */
65 | const fractal = module.exports = require('@frctl/fractal').create();
66 |
67 | /* Set the title of the project */
68 | fractal.set('project.title', 'FooCorp Component Library');
69 |
70 | /* Tell Fractal where the components will live */
71 | fractal.components.set('path', __dirname + '/src/components');
72 |
73 | /* Tell Fractal where the documentation pages will live */
74 | fractal.docs.set('path', __dirname + '/src/docs');
75 |
76 | ```
77 |
78 | A full list of project configuration options for the various parts of Fractal can be found within their dedicated documentations sections.
79 |
80 |
81 |
82 | ### 3. Create your first component
83 |
84 | Components can be very simple, consisting of just a single view template file, or much more complex. To get up and running we are going to just create the simplest possible component by adding a single file called `alert.hbs` into **the components directory**.
85 |
86 | ```html
87 |
88 |
This is an alert!
89 | ```
90 |
91 |
96 |
97 | Obviously this isn't a very exciting component at this point, but there is [plenty more you can do](./components/) once you've got to grips with the basics.
98 |
99 | ### 4. Add a documentation index page
100 |
101 | Next we'll add a Markdown file to act as our index page. The page will be called `index.md` and should live **in the documentation directory** (i.e. at `src/docs/index.md`).
102 |
103 | ```md
104 | ---
105 | title: FooCorp Components
106 | ---
107 | This is the component library for FooCorp. **Feel free to look around!**
108 | ```
109 |
110 | The Markdown file also contains some YAML front-matter to specify a title for the page - check out the [documentation pages section](./documentation/) for more details on this and all the other things that you can do with Fractal's powerful documentation engine.
111 |
112 | ### 5. Start the development server
113 |
114 | Now all that's left to do is to fire up the development server and have a look at your component library.
115 |
116 | Open up your terminal, make sure you are in the root of your project directory and use the following command to start the server:
117 |
118 | ```bash
119 | fractal start --sync
120 | ```
121 |
122 | ::: tip
123 | Note that using the `--sync` option here instructs Fractal to use BrowserSync to seamlessly watch your file system for changes and refresh the web UI when you make updates to your files.
124 | :::
125 |
126 | Once it has booted up you should see something like this in your terminal window:
127 |
128 |
129 |
130 | If so, visit the 'Local URL' (It should be something like [http://localhost:3000](http://localhost:3000)) and have a look at your component library's web UI.
131 |
132 | The [web UI docs](./web/) has full details on the options available when starting up development servers, as well as information on how to run static HTML exports of your component library UI and more.
133 |
--------------------------------------------------------------------------------
/docs/guide/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Installing Fractal
3 | ---
4 |
5 | # Installing Fractal
6 |
7 | Fractal is installed as a Node module in your project using NPM.
8 |
9 | There is also an (optional, but recommended) Command-Line Interface (CLI) tool which can be installed globally on your system, again using NPM.
10 |
11 | ## Installing Fractal in your project
12 |
13 | If you have not already created a folder for your project, do so now and then run `npm init` from within the folder to initialise your project directory.
14 |
15 | Once this is done, run the following command to install Fractal in your project:
16 |
17 | ```bash
18 | npm install --save @frctl/fractal
19 | ```
20 |
21 | ## Installing the Fractal CLI tool
22 |
23 | Fractal provides a globally-installable CLI tool to make running tasks such as starting the development web server quick and easy. This tool is completely optional - there are plenty of other options (including direct integration with [Gulp, NPM scripts or other build tool](./integration/build-tools.md) if you don't want to use it.
24 |
25 | To install the Fractal CLI tool, run the following command from your terminal:
26 |
27 | ```bash
28 | npm i -g @frctl/fractal
29 | ```
30 |
31 | You can then run tasks using the `fractal ` format from your terminal - see the [CLI tool documentation](./cli/) for full details.
32 |
--------------------------------------------------------------------------------
/docs/guide/integration/build-tools.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Build Tools
3 | ---
4 |
5 | # Integrating Fractal into build tools
6 |
7 | Fractal can happily be integrated into any JavaScript-based build tool by making use of [its API](../../api/), and can reduce or replace the need to use Fractal's own [CLI tool](../cli/) for running tasks such as starting the dev server.
8 |
9 | ## Gulp
10 |
11 | The following is an example `gulpfile.js` that defines two tasks, one to start the [dev server](../web/development-server.html) and one to [run a static export](../web/exporting-static-html.html) of the web UI.
12 |
13 | Once added, these can be run as `gulp fractal:start` and `gulp fractal:build`. However you can of course change them to be called whatever you like!
14 |
15 | ```js
16 | 'use strict';
17 |
18 | const gulp = require('gulp');
19 |
20 | /*
21 | * Configure a Fractal instance.
22 | *
23 | * This configuration could also be done in a separate file, provided that this file
24 | * then imported the configured fractal instance from it to work with in your Gulp tasks.
25 | * i.e. const fractal = require('./my-fractal-config-file');
26 | */
27 |
28 | const fractal = require('@frctl/fractal').create();
29 |
30 | fractal.set('project.title', 'FooCorp Component Library'); // title for the project
31 | fractal.web.set('builder.dest', 'build'); // destination for the static export
32 | fractal.docs.set('path', `${__dirname}/docs`); // location of the documentation directory.
33 | fractal.components.set('path', `${__dirname}/components`); // location of the component directory.
34 |
35 | // any other configuration or customisation here
36 |
37 | const logger = fractal.cli.console; // keep a reference to the fractal CLI console utility
38 |
39 | /*
40 | * Start the Fractal server
41 | *
42 | * In this example we are passing the option 'sync: true' which means that it will
43 | * use BrowserSync to watch for changes to the filesystem and refresh the browser automatically.
44 | * Obviously this is completely optional!
45 | *
46 | * This task will also log any errors to the console.
47 | */
48 |
49 | gulp.task('fractal:start', function(){
50 | const server = fractal.web.server({
51 | sync: true
52 | });
53 | server.on('error', err => logger.error(err.message));
54 | return server.start().then(() => {
55 | logger.success(`Fractal server is now running at ${server.url}`);
56 | });
57 | });
58 |
59 | /*
60 | * Run a static export of the project web UI.
61 | *
62 | * This task will report on progress using the 'progress' event emitted by the
63 | * builder instance, and log any errors to the terminal.
64 | *
65 | * The build destination will be the directory specified in the 'builder.dest'
66 | * configuration option set above.
67 | */
68 |
69 | gulp.task('fractal:build', function(){
70 | const builder = fractal.web.builder();
71 | builder.on('progress', (completed, total) => logger.update(`Exported ${completed} of ${total} items`, 'info'));
72 | builder.on('error', err => logger.error(err.message));
73 | return builder.build().then(() => {
74 | logger.success('Fractal build completed!');
75 | });
76 | });
77 |
78 | ```
79 |
80 | ## NPM Scripts
81 |
82 | Because the locally-installed Fractal module also includes the [CLI tool](../cli/) binary, you can use it in your NPM scripts to provide a convenient way to run CLI tasks without having to have the Fractal CLI tool installed globally.
83 |
84 | An example `package.json` file may therefore look like this:
85 |
86 | ```json
87 | {
88 | "name": "foocorp-component-library",
89 | "version": "1.0.0",
90 | "description": "FooCorp Component Library.",
91 | "devDependencies": {
92 | "@frctl/fractal": "…",
93 | },
94 | "scripts": {
95 | "start": "fractal start --sync",
96 | "build": "fractal build"
97 | }
98 | }
99 | ```
100 |
101 | One thing to note here is that because you can't directly configure your Fractal instance within your `package.json` file, you will still need to have a `fractal.config.js` file [in your project root](../project-settings.html) to contain all your project setup information.
102 |
--------------------------------------------------------------------------------
/docs/guide/integration/including-as-dependency.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Including as a dependency
3 | ---
4 |
5 | # Using your component library within other projects
6 |
7 | If you want to include your Fractal component library as a dependency in another project, one way to do so is to package it up as an Node module and import it via NPM.
8 |
9 | ## 1. Prepare your library for publishing
10 |
11 | To set up your library for publishing, you will need to:
12 |
13 | 1. Make sure that the [paths in your `fractal.config.js`](../project-settings.html) are full contextual paths (i.e. making use of the Node `__dirname` global)
14 | 2. Set a name for your component library in your `package.json` file - for instance `foocorp-component-library`.
15 | 2. Set the value of the [main](https://docs.npmjs.com/files/package.json#main) field in your package.json to be `fractal.config.js`.
16 | 3. Either publish to NPM as a module or push to Github. Full details of publishing and consuming NPM modules is outside the scope of these docs but there are plenty of good tutorials on the web.
17 |
18 | ## 2. Include in your project
19 |
20 | In the project that you want to include the fractal component library in:
21 |
22 | 1. Install fractal: `npm i @frctl/fractal`
23 | 2. Install your component library: `npm i foocorp-component-library`
24 | 3. Create a `fractal.config.js` file in the root of your project that looks as follows:
25 |
26 | ```js
27 | const fractal = module.exports = require('foocorp-component-library');
28 |
29 | // any other custom, instance specific configuration here if needed
30 | ```
31 |
32 | You should now be able to run fractal commands such as `fractal start` from within the parent project's root directory and they will operate on your component library as if it were part of the project itself.
33 |
34 | ## 3. Next steps
35 |
36 | Obviously just including the component library into another project is not that useful by itself - you now need to decide how you want to _consume_ that component library code in your project.
37 |
38 | Generally you have a number of options, the primary ones being:
39 |
40 | 1. Use the Fractal API to directly include and render components within your application (only applicable if you are building a Node.JS app)
41 | 2. Write a bespoke template loader for your project that loads templates from your library, perhaps making use of a mapping of component handles -> paths that can be generated by Fractal.
42 | 3. Export the templates from your library into your project, possibly with some path re-writing as part of the export process, and then consume these exported templates in your project as required.
43 |
44 | For example, a [bespoke Fractal CLI task](../cli/custom-commands.html) for **option 3** might look something like:
45 |
46 | ```js
47 | // setup/import etc...
48 |
49 | const fs = require('fs');
50 | const path = require('path');
51 |
52 | /*
53 | * Fractal export command.
54 | *
55 | * Exports all view templates into a directory in the root of the project.
56 | * Templates are exported in a flat structure with the filenames in the format of {handle}.{ext}
57 | * Requires either an output directory that exists, or uses `exported` if it exists
58 | *
59 | * Any @handle references in the templates (for partial includes etc) are re-written
60 | * to reference the appropriate template path.
61 | *
62 | * Run by using the command `fractal export` in the root of the project directory.
63 | */
64 | function exportTemplates(args, done) {
65 |
66 | const app = this.fractal;
67 | const items = app.components.flattenDeep().toArray();
68 | const jobs = [];
69 |
70 | for (const item of items) {
71 |
72 | const exportPath = path.join('./', args.options.output || 'exported', `${item.alias || item.handle}${app.get('components.ext')}`);
73 | const job = item.getContent().then(str => {
74 | return str.replace(/\@([0-9a-zA-Z\-\_]*)/g, function(match, handle){
75 | return `${handle}${app.get('components.ext')}`;
76 | });
77 | }).then(str => {
78 | return fs.writeFileSync(exportPath, str);
79 | });
80 |
81 | jobs.push(job);
82 | }
83 |
84 | return Promise.all(jobs);
85 | }
86 |
87 | fractal.cli.command('export', exportTemplates, {
88 | description: 'Export all component templates',
89 | options: [
90 | ['-o, --output ', 'The directory to export components into, relative to the CWD.'],
91 | ]
92 | });
93 |
94 | ```
95 |
--------------------------------------------------------------------------------
/docs/guide/integration/integrating-into-production.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Integrating into production
3 | ---
4 |
5 | # Integrating into production
6 |
7 | It is often desirable to have some form of integration between your component library and your production site or application.
8 |
9 | However, each project is different, and each one will have its own set of constraints and requirements that will determine the best way to perform this integration.
10 |
11 | Instead of constraining you to a particular approach, Fractal instead exposes a [full-featured API](../../api/) to allow access to its underlying data model and rendering engine. This means that you can include it directly into your application as a dependency, or into your build tools to enable you to export templates, assets or whatever else you need and in the best format to make integration as painless as possible.
12 |
13 | There are however some common patterns around this, some of which will be outlined below.
14 |
15 | ::: warning Coming soon...
16 | Examples coming soon.
17 | :::
18 |
--------------------------------------------------------------------------------
/docs/guide/project-settings.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Project Settings
3 | ---
4 |
5 | # Project Settings and Configuration
6 |
7 | Fractal is very flexible when it comes to things like project structure and organisation, and also offers many ways to customise things like view template engines and themes for the web UI.
8 |
9 | Fractal comes with a few sensible defaults, but before you can get your project up and running you will generally need to provide some additional configuration information.
10 |
11 | ## The fractal.config.js file
12 |
13 | By convention, project configuration and setup information should be kept in a file called `fractal.config.js` that lives in the **root of your project directory**.
14 |
15 | ::: tip
16 | Note that previously the config file was called `fractal.js` by default. This changed in v1.3.0.
17 | :::
18 |
19 | If you are using the Fractal [CLI tool](./cli/) this file will need to exist (and be set up correctly) before you can run commands on your project.
20 |
21 | ::: tip A note on paths
22 | When setting paths to directories in your Fractal configuration, it's possible to specify them relative to the root of your project directory - i.e. `src/components`. However it's recommended that you instead make use of Node's [`\__dirname`](https://nodejs.org/docs/latest/api/globals.html#globals_dirname) global to generate full absolute paths that look like:
23 |
24 | `const myPath = __dirname + '/src/components';`
25 |
26 | This will make your Fractal installation more portable (and more robust for any later integrations). All examples in this documentation will use this style.
27 | :::
28 |
29 | ### Creating and exporting a new Fractal instance
30 |
31 | At a bare minimum, your `fractal.config.js` file must `require` the Fractal module, create a new instance and then export it (so that other tools such as the CLI tool can make use of it). In the example below we are doing all this in a handy one-liner:
32 |
33 | ```js
34 | 'use strict';
35 | const fractal = module.exports = require('@frctl/fractal').create();
36 | ```
37 |
38 | ### Project-related metadata
39 |
40 | Most projects will want to customise the project title from the default. This can be done using the [`fractal.set()`](../api/endpoints/fractal.html#set-path-value) method as follows:
41 |
42 | ```js
43 | fractal.set('project.title', 'FooCorp Component Library');
44 | ```
45 |
46 | Any other project metadata that you may want to store for use in you app can be set on `project.*` keys as required. For instance you may want to keep a reference to your project version and author:
47 |
48 | ```js
49 | fractal.set('project.version', 'v1.0');
50 | fractal.set('project.author', 'Mickey Mouse');
51 | ```
52 |
53 | Apart from the `project.title` value, Fractal will not use any of these other values directly, but you can use them in your pages and components should you wish.
54 |
55 | ### Configuring components
56 |
57 | Component configuration is done using the [`fractal.components.set()`](../api/endpoints/fractal-components.html#set-path-value) method.
58 |
59 | To specify the directory that your [components](./components/) will be created in, you can use the `path` setting:
60 |
61 | ```js
62 | fractal.components.set('path', __dirname + '/src/components');
63 | ```
64 |
65 | The [components configuration reference](./components/configuration-reference.md) contains details of all the other options that you may want to tweak for the components in your project.
66 |
67 |
68 | ### Configuring documentation pages
69 |
70 | Docs configuration is done using the [`fractal.docs.set()`](../api/endpoints/fractal-docs.html#set-path-value) method.
71 |
72 | To specify the directory that your [documentation pages](./documentation/) will reside in, you can use the `path` setting:
73 |
74 | ```js
75 | fractal.docs.set('path', __dirname + '/src/docs');
76 | ```
77 |
78 | The [documentation pages configuration reference](./documentation/configuration-reference.html) contains details of all the other available documentation configuration options.
79 |
80 | ### Configuring the web UI
81 |
82 | Web UI configuration is done using the [`fractal.web.set()`](../api/endpoints/fractal-web.html#set-path-value) method.
83 |
84 | To serve a directory of [static assets](./web/#static-assets) via the web UI (so that you can link to stylesheets from your preview layouts, for example), you can specify the path to the directory using the `static.path` setting:
85 |
86 | ```js
87 | fractal.web.set('static.path', __dirname + '/public');
88 | ```
89 |
90 | To set the directory within which any [static HTML exports](./web/exporting-static-html.html) of the web UI should be generated, use the `builder.dest` setting:
91 |
92 | ```js
93 | fractal.web.set('builder.dest', __dirname + '/build');
94 | ```
95 |
96 | The [web UI configuration reference](./web/configuration-reference.html) contains details of all the other available web configuration options.
97 |
98 | ## Example project setup file
99 |
100 | Tying together the examples above, we can see that a basic `fractal.config.js` file might look something like this:
101 |
102 | ```js
103 | 'use strict';
104 |
105 | /* Create a new Fractal instance and export it for use elsewhere if required */
106 | const fractal = module.exports = require('@frctl/fractal').create();
107 |
108 | /* Set the title of the project */
109 | fractal.set('project.title', 'FooCorp Component Library');
110 |
111 | /* Tell Fractal where the components will live */
112 | fractal.components.set('path', __dirname + '/src/components');
113 |
114 | /* Tell Fractal where the documentation pages will live */
115 | fractal.docs.set('path', __dirname + '/src/docs');
116 |
117 | /* Specify a directory of static assets */
118 | fractal.web.set('static.path', __dirname + '/public');
119 |
120 | /* Set the static HTML build destination */
121 | fractal.web.set('builder.dest', __dirname + '/build');
122 |
123 | ```
124 |
125 |
126 |
129 |
--------------------------------------------------------------------------------
/docs/guide/upgrading.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Upgrading
3 | ---
4 |
5 | # Upgrade Guide
6 |
7 | ## Upgrading from a pre-1.0 version
8 |
9 | If you have been using a pre-1.0 version of Fractal, you will need to update both the local Fractal version in your project dependencies **and** your Fractal CLI tool version.
10 |
11 | ### CLI tool
12 |
13 | Update your CLI tool to the latest version:
14 |
15 | ```bash
16 | npm i -g @frctl/fractal
17 | ```
18 |
19 | ### Per-project dependencies
20 |
21 | Update the Fractal version in your project's `package.json` file:
22 |
23 | ```js
24 | {
25 | "dependencies": {
26 | "@frctl/fractal": "^1.0.0"
27 | }
28 | }
29 | ```
30 |
31 | Then run `npm update` from within your project directory to install the latest 1.x version of Fractal.
32 |
33 | ### Breaking changes
34 |
35 | Fractal v1.x contains a number of breaking changes with respect to the 0.x branch. Most of which are centered around project setup and configuration.
36 |
37 | * **Project setup:** See the [project setup](./project-settings.md) documentation for details on the updated syntax for creating and configuring a new Fractal instance.
38 | * **Template engines**: The syntax for registering and configuring template engines has changed. See the documentation for the [default Handlebars engine](./core-concepts/view-templates.md) and the [template engine customisation](./customisation/template-engines.md) documentation for full details.
39 | * **Themes**: Theme loading and configuration has had significant changes, and the default theme (Mandelbrot) has been updated accordingly. See the [Mandelbrot](./web/default-theme.md) and the more general [web theme customisation](./customisation/web-themes.md) docs for info.
40 |
--------------------------------------------------------------------------------
/docs/guide/web/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | # Web UI
6 |
7 | The Fractal web UI provides a web-based interface to browse your components and their associated files, as well as view project documentation and assets.
8 |
9 | It can be run as via an in-built development server or exported to static HTML.
10 |
11 | If you are using the Fractal CLI tool, you can start the local web UI server (and watch the file system for changes) with the `start` command from within the root of your project directory:
12 |
13 | ```bash
14 | fractal start --watch
15 | ```
16 |
17 | See the [dev server](./development-server.html) documentation for more information and configuration options.
18 |
19 |
20 | ## Configuration
21 |
22 | You can configure various aspects of the web UI using the [`fractal.web.set()`](../../api/endpoints/fractal-web.html#set-path-value) method. For example, to use the integrated BrowserSync option by default, you can set the `sync` option to `true` as follows:
23 |
24 | ```js
25 | fractal.web.set('server.sync', true);
26 | ```
27 |
28 | ::: warning
29 | Only [core web configuration](./configuration-reference.html) options can be set using the [`fractal.web.set()`](../../api/endpoints/fractal-web.html#set-path-value) method. Theme-specific configuration options must be set on the theme instance itself.
30 |
31 | See the [default theme docs](./default-theme.html#configuration) or the [themes customisation guide](../customisation/web-themes.html) for more information.
32 | :::
33 |
34 | ## Static Assets
35 |
36 | Most projects will have a directory of static assets (such as compiled stylesheets, JavaScript files, images etc) that need to be used by [components](../components/) or linked to from within [preview layouts](../components/preview-layouts.html).
37 |
38 | To serve static assets from within the web UI you can use the `static.path` configuration option to specify the path to a directory of assets:
39 |
40 | ```js
41 | fractal.web.set('static.path', __dirname + '/public');
42 | ```
43 |
44 | All files within that directory will now be made available at a URL that matches the file's path relative to the directory. For example, given the following project structure (and the configuration setting above):
45 |
46 | ```
47 | ├── components
48 | │ └── ...
49 | ├── public
50 | │ ├── css
51 | │ │ └── example.css
52 | │ └── js
53 | │ └── scripts.js
54 | ```
55 |
56 | The the dev server will serve up the CSS and JS files at the URLs `/css/example.css` and `/js/scripts.js` respectively.
57 |
58 | If you want to prefix the URL path of the assets that are being served up, you can do so with the `static.mount` option:
59 |
60 | ```js
61 | fractal.web.set('static.mount', 'foobar');
62 | ```
63 |
64 | The the dev server will now serve up the CSS and JS files from the previous example at the URLs `/foobar/css/example.css` and `/foobar/js/scripts.js` respectively.
65 |
66 | ### Linking to assets from view templates
67 |
68 | If you want to link to any of your static assets from your components or preview layouts, it is **strongly recommended** that you use the supplied Handlebars [`path` helper](../core-concepts/view-templates.html#handlebars-helpers) to do so:
69 |
70 | ```
71 | {{path '/foobar/css/example.css'}}
72 | ```
73 |
74 | This helper lets you specify the static asset path as a root-relative URL such as `/foobar/css/example.css` and will then automatically take care of any path-rewriting necessary to support the [static HTML export process](./exporting-static-html.html).
75 |
76 |
79 |
80 |
81 | ## Themes
82 |
83 | The web UI is built upon *themes*. Themes are very powerful, and allow complete control over everything from look and feel to URLs and functionality. Themes can be used to customise the look and feel of the web UI to match your project or even to give a completely different 'view' of your component library to different project stakeholders - for instance a 'no code' theme for people that might only be interested in reviewing the component previews.
84 |
85 | The [default theme](./default-theme.html) (called 'Mandelbrot') that ships with Fractal also supports a number of customisation options if you don't want to roll your own custom theme from scratch.
86 |
87 |
96 |
--------------------------------------------------------------------------------
/docs/guide/web/configuration-reference.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Configuration reference
3 | ---
4 |
5 | # Web UI configuration
6 |
7 | There are a number of global configuration options available to customise the behaviour of both the [development web server](./development-server.html) and the [static HTML builder](../web/exporting-static-html.html).
8 |
9 | These options can be set on your Fractal instance using the [`fractal.web.set()`](../../api/endpoints/fractal-web.html#set-path-value) method. See the [project settings](../project-settings.html) documentation for more details.
10 |
11 | ### builder.concurrency
12 |
13 | How many concurrent export tasks to run at any one time. Useful if you are experiencing filesystem write errors when running the builder. More is not necessarily faster!
14 |
15 | ```js
16 | fractal.web.set('builder.concurrency', 5); // default is 10
17 | ```
18 |
19 | ### builder.dest
20 |
21 | Path to the folder that the static HTML build should be exported to.
22 |
23 | ```js
24 | fractal.web.set('builder.dest', __dirname + '/export');
25 | ```
26 |
27 | ### builder.ext
28 |
29 | The file extension that should be used for the exported HTML pages.
30 |
31 | ```js
32 | fractal.web.set('builder.ext', '.php'); // default is '.html'
33 | ```
34 |
35 | ### builder.urls.ext
36 |
37 | The file extension that should be used when rewriting URLs for the static export.
38 |
39 | If you are going to be serving the exported content via a web server and want to have 'pretty' URLs, then setting this to `null` (to generate extension-less URLs) and then doing some URL-rewriting on the server (using an `.htaccess` file or equivalent) is often a good solution.
40 |
41 | ```js
42 | fractal.web.set('builder.urls.ext', null); // default is '.html'
43 | ```
44 |
45 | ### server.sync
46 |
47 | Whether or not to use [BrowserSync](http://browsersync.io) to watch the filesystem and reload the web UI when changes occur.
48 |
49 | ```js
50 | fractal.web.set('server.sync', true); // default is false
51 | ```
52 |
53 | ### server.syncOptions
54 |
55 | An object of options to pass to the underlying BrowserSync instance when using the `sync` option described above.
56 |
57 | ```js
58 | fractal.web.set('server.syncOptions', {
59 | open: true,
60 | browser: ['google chrome', 'firefox'],
61 | notify: true
62 | });
63 | ```
64 |
65 | See the [BrowserSync documentation](https://www.browsersync.io/docs/options) for a full list of available options.
66 |
67 | ### server.port
68 |
69 | Hard-code a port number to start the server on. Generally this option is not required because Fractal will automatically find an available port to use.
70 |
71 | ```js
72 | fractal.web.set('server.port', 4444); // default is null
73 | ```
74 |
75 | ### server.watch
76 |
77 | Whether to watch the filesystem for changes and trigger the re-building of the underlying data objects when updates occur.
78 |
79 | This is effectively a light-weight alternative to the `server.sync` option, although it lacks any reload functionality or any of the advanced options that BrowserSync provides.
80 |
81 | ```js
82 | fractal.web.set('server.watch', true); // default is false
83 | ```
84 |
85 | ### static.path
86 |
87 | The path to the directory where your static assets live. Any assets within this directory will be made available to your components and preview layouts at a URL path relative to this directory. See the [static assets](../web/#static-assets) documentation for more details.
88 |
89 | ```js
90 | fractal.web.set('static.path', __dirname + '/public');
91 | // public/bar/foo.css will be served at http://localhost:3000/bar/foo.css
92 | ```
93 |
94 | ### static.mount
95 |
96 | Virtual path prefix for the files that are served from the static asset directory specified in the `static.path` option. See the [static assets](../web/#static-assets) documentation for more details.
97 |
98 | ```js
99 | fractal.web.set('static.mount', 'project-assets');
100 | // public/bar/foo.css will be served at http://localhost:3000/project-assets/bar/foo.css
101 | ```
102 |
103 | ### highlighter
104 |
105 | Override and/or extend the default [highlight.js](https://github.com/highlightjs/highlight.js/) syntax highlighter.
106 |
107 | For example, adding Svelte language support to highlight.js:
108 | ```js
109 | const hljs = require('highlight.js');
110 | const hljsSvelte = require('highlightjs-svelte');
111 | const _ = require('lodash');
112 |
113 | hljsSvelte(hljs);
114 |
115 | fractal.web.set('highlighter', function (content, lang) {
116 | content = _.toString(content || '');
117 | lang = lang ? lang.toLowerCase() : lang;
118 | try {
119 | return lang ? hljs.highlight(lang, content).value : hljs.highlightAuto(content).value;
120 | } catch (e) {
121 | return hljs.highlightAuto(content).value;
122 | }
123 | });
124 | ```
125 |
126 |
127 |
--------------------------------------------------------------------------------
/docs/guide/web/development-server.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Development Server
3 | ---
4 |
5 | # Development server
6 |
7 | Fractal comes with a local development server for running the web UI while you are building your component library.
8 |
9 | ## Starting the server
10 |
11 | You can either start the server using the Fractal CLI tool (if you are using it) or programmatically using Fractal's API.
12 |
13 | ### Using the CLI tool
14 |
15 | You can use the `start` command from within the root of your project to get the server up and running:
16 |
17 | ```bash
18 | fractal start
19 | ```
20 |
21 | You can provide the following (optional) command line options to override the default configuration:
22 |
23 | * `-p, --port ` - the port number to use, for example `5000`.
24 | * `-t, --theme ` - the custom theme to use.
25 | * `-s, --sync` - whether to use the integrate [BrowserSync](#browsersync-integration) instance to provide auto-refresh and syncing capabilities
26 | * `-w, --watch` - whether to watch components and documentation pages for changes
27 |
28 | As an example, the command:
29 |
30 | ```bash
31 | fractal start --watch --port 4000
32 | ```
33 |
34 | Would start the preview server at the URL [`http://localhost:4000`](http://localhost:4000) and start watching the filesystem for changes.
35 |
36 | ### Programmatically
37 |
38 | If you wish to start the server programmatically, (often useful for [build tool](../integration/build-tools.html) integrations), you can create a new server instance using the [`fractal.web.server()`](../../api/endpoints/fractal-docs.html#set-path-value) method and then start and stop it as required:
39 |
40 | ```js
41 | const server = fractal.web.server();
42 |
43 | server.start().then(function(){
44 | console.log(`Fractal server is now running at ${server.url}`);
45 | });
46 |
47 | server.stop();
48 | ```
49 |
50 | The [`Server`](../../api/entities/server.html) object returned by the call to `fractal.web.server()` is a Node EventEmitter and will emit error events (and others) that you can bind to. See the [`fractal.web`](../../api/endpoints/fractal-web.html) API docs for full details.
51 |
52 | ## BrowserSync integration
53 |
54 | The Fractal web server includes a seamless integration with BrowserSync, should you require it.
55 |
56 | When enabled, it provides:
57 |
58 | * Auto-reloading of the web UI when files change
59 | * Re-injecting of static assets (such as stylesheets) when changes are made
60 | * A network-accessible URL for device testing
61 | * Syncing of page navigation between tabs
62 | * Lots more - see the [BrowserSync website](https://www.browsersync.io/) for details.
63 |
64 | BrowserSync can be enabled as a global option, when starting the server via the CLI tool or programmatically:
65 |
66 | ### Enabling globally
67 |
68 | You can [configure](../project-settings.html) your Fractal instance to use BrowserSync integration whenever the server is started as follows:
69 |
70 | ```js
71 | fractal.web.set('server.sync', true);
72 | ```
73 |
74 | You can also pass [options](https://www.browsersync.io/docs/options) to the underlying BrowserSync instance using the `server.syncOptions` property:
75 |
76 | ```js
77 | fractal.web.set('server.syncOptions', {
78 | open: true,
79 | browser: ['google chrome', 'firefox'],
80 | notify: true
81 | });
82 | ```
83 |
84 | ### Using the CLI tool
85 |
86 | You can use the `--sync` option to enable BrowserSync when starting the server:
87 |
88 | ```bash
89 | fractal start --sync
90 | ```
91 |
92 | ### Programmatically
93 |
94 | You can set the `sync` option to `true` in the server config object when getting a new server instance:
95 |
96 | ```js
97 | const server = fractal.web.server({
98 | sync: true
99 | });
100 |
101 | server.start().then(function(){
102 | console.log(`Local URL: ${server.url}`);
103 | console.log(`Network URL: ${server.urls.sync.external}`);
104 | });
105 | ```
106 |
--------------------------------------------------------------------------------
/docs/guide/web/exporting-static-html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Exporting to static HTML
3 | ---
4 |
5 | # Exporting to static HTML
6 |
7 | Fractal provides the option to export the web UI view into static HTML files, which can quickly and easily be shared with clients or hosted using a simple static file server.
8 |
9 | ::: tip
10 | When developing locally you'll want to use the [local development server](./development-server.html) to preview your project while you work on it, rather than running repeated exports after changes have been made.
11 | :::
12 |
13 | ## Configuration
14 |
15 | Before you can run the build step you need to set a build destination for your Fractal instance:
16 |
17 | ```js
18 | fractal.web.set('builder.dest', __dirname + '/build');
19 | ```
20 |
21 | ## Running the build
22 |
23 | You can either start the export using the Fractal CLI tool (if you are using it) or programmatically using Fractal's API.
24 |
25 | ### Using the CLI tool
26 |
27 | You can use the `build` command from within the root of your project to get the server up and running:
28 |
29 | ```bash
30 | fractal build
31 | ```
32 |
33 | You can provide the following optional command line options to override the default configuration:
34 |
35 | * `-t, --theme ` - a custom theme to use.
36 |
37 | ### Programmatically
38 |
39 | If you wish to start the export process programmatically, (often useful for [build tool](../integration/build-tools.html) integrations), you can create a new builder instance using the [`fractal.web.builder()`](../../api/endpoints/fractal-web.html#builder) method and then start it as required:
40 |
41 | ```js
42 | const builder = fractal.web.builder();
43 |
44 | builder.build().then(function(){
45 | console.log(`Fractal static HTML build complete!`);
46 | });
47 | ```
48 |
49 | The [`Builder`](../../api/entities/builder.html) object returned by the call to `fractal.web.builder()` is a Node EventEmitter and will emit error events (and others) that you can bind to. See the [`fractal.web`](../../api/endpoints/fractal-web.html) API docs for full details.
50 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "docs/.vuepress/dist"
3 | command = "npm run build"
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fractal-docs",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/frctl/fractal-docs.git"
8 | },
9 | "license": "MIT",
10 | "devDependencies": {
11 | "vuepress": "^1.7.1"
12 | },
13 | "scripts": {
14 | "start": "vuepress dev docs",
15 | "build": "vuepress build docs"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------