├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── bug.md │ ├── config.yml │ └── feature.md ├── dependabot.yml └── workflows │ ├── release.yml │ └── test.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .stylelintrc.js ├── LICENSE ├── README.md ├── babel.config.js ├── examples ├── README.md ├── adapter-tests │ ├── CHANGELOG.md │ ├── package.json │ └── src │ │ ├── collated.js │ │ ├── components.js │ │ ├── context.js │ │ ├── docs.js │ │ ├── include.js │ │ ├── index.js │ │ ├── notes.js │ │ ├── path.js │ │ ├── render-tag.js │ │ ├── render.js │ │ └── tree.js ├── handlebars │ ├── CHANGELOG.md │ ├── README.md │ ├── components │ │ ├── collated │ │ │ ├── __snapshots__ │ │ │ │ └── collated.spec.js.snap │ │ │ ├── collated.config.js │ │ │ ├── collated.hbs │ │ │ └── collated.spec.js │ │ ├── components.spec.js │ │ ├── context-data │ │ │ ├── a.config.yml │ │ │ ├── a.hbs │ │ │ ├── b.config.yml │ │ │ ├── b.hbs │ │ │ ├── config.yml │ │ │ └── context-data.spec.js │ │ ├── context │ │ │ ├── __snapshots__ │ │ │ │ └── context.spec.js.snap │ │ │ ├── async │ │ │ │ ├── async.config.js │ │ │ │ └── async.hbs │ │ │ ├── context.spec.js │ │ │ ├── js │ │ │ │ ├── js.config.js │ │ │ │ └── js.hbs │ │ │ ├── json │ │ │ │ ├── json.config.json │ │ │ │ └── json.hbs │ │ │ ├── reference-full │ │ │ │ ├── reference-full.config.yml │ │ │ │ └── reference-full.hbs │ │ │ ├── reference-key │ │ │ │ ├── reference-key.config.yml │ │ │ │ └── reference-key.hbs │ │ │ ├── reference │ │ │ │ ├── reference.config.yml │ │ │ │ └── reference.hbs │ │ │ └── yaml │ │ │ │ ├── yaml.config.yml │ │ │ │ └── yaml.hbs │ │ ├── include │ │ │ ├── __snapshots__ │ │ │ │ └── include.spec.js.snap │ │ │ ├── include-child │ │ │ │ └── include-child.hbs │ │ │ ├── include-parent │ │ │ │ ├── include-parent--self.hbs │ │ │ │ └── include-parent.hbs │ │ │ └── include.spec.js │ │ ├── notes │ │ │ ├── notes-config │ │ │ │ ├── notes-config.config.yml │ │ │ │ └── notes-config.hbs │ │ │ ├── notes-files │ │ │ │ ├── notes-files--alt.hbs │ │ │ │ ├── notes-files--alt.readme.md │ │ │ │ ├── notes-files.hbs │ │ │ │ └── notes-files.readme.md │ │ │ └── notes.spec.js │ │ ├── one-very-very-long-component-name.hbs │ │ ├── partial-block │ │ │ ├── config.yml │ │ │ ├── parent.hbs │ │ │ ├── partial-block.spec.js │ │ │ └── partial.hbs │ │ ├── path │ │ │ ├── __snapshots__ │ │ │ │ └── path.spec.js.snap │ │ │ ├── path.hbs │ │ │ └── path.spec.js │ │ ├── render-tag │ │ │ ├── comp-1.config.yml │ │ │ ├── comp-1.hbs │ │ │ ├── comp-2--escaped-handle.hbs │ │ │ ├── comp-2--missing-handle.hbs │ │ │ ├── comp-2--no-context.hbs │ │ │ ├── comp-2--variant.hbs │ │ │ ├── comp-2--wrong-handle.hbs │ │ │ ├── comp-2.config.yml │ │ │ ├── comp-2.hbs │ │ │ ├── config.yml │ │ │ ├── escaped-handle.config.yml │ │ │ ├── escaped-handle.hbs │ │ │ └── render-tag.spec.js │ │ ├── render │ │ │ ├── __snapshots__ │ │ │ │ └── render.spec.js.snap │ │ │ ├── render--camelCaseVariant.hbs │ │ │ ├── render--variant-2.hbs │ │ │ ├── render.config.yml │ │ │ ├── render.hbs │ │ │ └── render.spec.js │ │ ├── root │ │ │ ├── root-tree │ │ │ │ └── root-tree-leaf.hbs │ │ │ └── root.config.yml │ │ └── tree │ │ │ ├── subtree │ │ │ ├── subtree-leaf │ │ │ │ ├── subtree-leaf--variant.hbs │ │ │ │ ├── subtree-leaf.config.yml │ │ │ │ └── subtree-leaf.hbs │ │ │ └── subtree.config.yml │ │ │ ├── tree-leaf │ │ │ ├── tree-leaf--variant.hbs │ │ │ ├── tree-leaf.config.yml │ │ │ └── tree-leaf.hbs │ │ │ ├── tree.config.yml │ │ │ └── tree.spec.js │ ├── docs │ │ ├── 01-index.md │ │ ├── __snapshots__ │ │ │ └── docs.spec.js.snap │ │ └── docs.spec.js │ ├── fractal.config.js │ ├── package.json │ └── public │ │ └── .gitkeep ├── nunjucks │ ├── CHANGELOG.md │ ├── README.md │ ├── components │ │ ├── collated │ │ │ ├── __snapshots__ │ │ │ │ └── collated.spec.js.snap │ │ │ ├── collated.config.js │ │ │ ├── collated.njk │ │ │ └── collated.spec.js │ │ ├── components.spec.js │ │ ├── context │ │ │ ├── __snapshots__ │ │ │ │ └── context.spec.js.snap │ │ │ ├── async │ │ │ │ ├── async.config.js │ │ │ │ └── async.njk │ │ │ ├── context.spec.js │ │ │ ├── js │ │ │ │ ├── js.config.js │ │ │ │ └── js.njk │ │ │ ├── json │ │ │ │ ├── json.config.json │ │ │ │ └── json.njk │ │ │ ├── reference-full │ │ │ │ ├── reference-full.config.yml │ │ │ │ └── reference-full.njk │ │ │ ├── reference-key │ │ │ │ ├── reference-key.config.yml │ │ │ │ └── reference-key.njk │ │ │ ├── reference │ │ │ │ ├── reference.config.yml │ │ │ │ └── reference.njk │ │ │ └── yaml │ │ │ │ ├── yaml.config.yml │ │ │ │ └── yaml.njk │ │ ├── include │ │ │ ├── __snapshots__ │ │ │ │ └── include.spec.js.snap │ │ │ ├── include-child │ │ │ │ └── include-child.njk │ │ │ ├── include-parent │ │ │ │ ├── include-parent--self.njk │ │ │ │ └── include-parent.njk │ │ │ └── include.spec.js │ │ ├── notes │ │ │ ├── notes-config │ │ │ │ ├── notes-config.config.yml │ │ │ │ └── notes-config.njk │ │ │ ├── notes-files │ │ │ │ ├── notes-files--alt.njk │ │ │ │ ├── notes-files--alt.readme.md │ │ │ │ ├── notes-files.njk │ │ │ │ └── notes-files.readme.md │ │ │ └── notes.spec.js │ │ ├── path │ │ │ ├── __snapshots__ │ │ │ │ └── path.spec.js.snap │ │ │ ├── path.njk │ │ │ └── path.spec.js │ │ ├── render-tag │ │ │ ├── comp-1.config.yml │ │ │ ├── comp-1.njk │ │ │ ├── comp-2--escaped-handle.njk │ │ │ ├── comp-2--missing-handle.njk │ │ │ ├── comp-2--no-context.njk │ │ │ ├── comp-2--variant.njk │ │ │ ├── comp-2--wrong-handle.njk │ │ │ ├── comp-2.config.yml │ │ │ ├── comp-2.njk │ │ │ ├── config.yml │ │ │ ├── escaped-handle.config.yml │ │ │ ├── escaped-handle.njk │ │ │ └── render-tag.spec.js │ │ ├── render │ │ │ ├── __snapshots__ │ │ │ │ └── render.spec.js.snap │ │ │ ├── render--camelCaseVariant.njk │ │ │ ├── render--variant-2.njk │ │ │ ├── render.config.yml │ │ │ ├── render.njk │ │ │ └── render.spec.js │ │ ├── root │ │ │ ├── root-tree │ │ │ │ └── root-tree-leaf.njk │ │ │ └── root.config.yml │ │ └── tree │ │ │ ├── subtree │ │ │ ├── subtree-leaf │ │ │ │ ├── subtree-leaf--variant.njk │ │ │ │ ├── subtree-leaf.config.yml │ │ │ │ └── subtree-leaf.njk │ │ │ └── subtree.config.yml │ │ │ ├── tree-leaf │ │ │ ├── tree-leaf--variant.njk │ │ │ ├── tree-leaf.config.yml │ │ │ └── tree-leaf.njk │ │ │ ├── tree.config.yml │ │ │ └── tree.spec.js │ ├── docs │ │ ├── 01-index.md │ │ ├── __snapshots__ │ │ │ └── docs.spec.js.snap │ │ └── docs.spec.js │ ├── fractal.config.js │ ├── package.json │ └── public │ │ └── .gitkeep ├── react │ ├── CHANGELOG.md │ ├── README.md │ ├── components │ │ ├── _preview.jsx │ │ ├── collated │ │ │ ├── __snapshots__ │ │ │ │ └── collated.spec.js.snap │ │ │ ├── collated.config.js │ │ │ ├── collated.jsx │ │ │ └── collated.spec.js │ │ ├── components.spec.js │ │ ├── context │ │ │ ├── __snapshots__ │ │ │ │ └── context.spec.js.snap │ │ │ ├── async │ │ │ │ ├── async.config.js │ │ │ │ └── async.jsx │ │ │ ├── context.spec.js │ │ │ ├── js │ │ │ │ ├── js.config.js │ │ │ │ └── js.jsx │ │ │ ├── json │ │ │ │ ├── json.config.json │ │ │ │ └── json.jsx │ │ │ ├── reference-full │ │ │ │ ├── reference-full.config.yml │ │ │ │ └── reference-full.jsx │ │ │ ├── reference-key │ │ │ │ ├── reference-key.config.yml │ │ │ │ └── reference-key.jsx │ │ │ ├── reference │ │ │ │ ├── reference.config.yml │ │ │ │ └── reference.jsx │ │ │ └── yaml │ │ │ │ ├── yaml.config.yml │ │ │ │ └── yaml.jsx │ │ ├── include │ │ │ ├── __snapshots__ │ │ │ │ └── include.spec.js.snap │ │ │ ├── include-child │ │ │ │ └── include-child.jsx │ │ │ ├── include-parent │ │ │ │ ├── include-parent--self.jsx │ │ │ │ └── include-parent.jsx │ │ │ └── include.spec.js │ │ ├── notes │ │ │ ├── notes-config │ │ │ │ ├── notes-config.config.yml │ │ │ │ └── notes-config.jsx │ │ │ ├── notes-files │ │ │ │ ├── notes-files--alt.jsx │ │ │ │ ├── notes-files--alt.readme.md │ │ │ │ ├── notes-files.jsx │ │ │ │ └── notes-files.readme.md │ │ │ └── notes.spec.js │ │ ├── path │ │ │ ├── __snapshots__ │ │ │ │ └── path.spec.js.snap │ │ │ ├── path.jsx │ │ │ └── path.spec.js │ │ ├── render │ │ │ ├── __snapshots__ │ │ │ │ └── render.spec.js.snap │ │ │ ├── render--camelCaseVariant.jsx │ │ │ ├── render--es6-import-export.jsx │ │ │ ├── render--variant-2.jsx │ │ │ ├── render.config.yml │ │ │ ├── render.jsx │ │ │ └── render.spec.js │ │ ├── root │ │ │ ├── root-tree │ │ │ │ └── root-tree-leaf.jsx │ │ │ └── root.config.yml │ │ ├── tree │ │ │ ├── subtree │ │ │ │ ├── subtree-leaf │ │ │ │ │ ├── subtree-leaf--variant.jsx │ │ │ │ │ ├── subtree-leaf.config.yml │ │ │ │ │ └── subtree-leaf.jsx │ │ │ │ └── subtree.config.yml │ │ │ ├── tree-leaf │ │ │ │ ├── tree-leaf--variant.jsx │ │ │ │ ├── tree-leaf.config.yml │ │ │ │ └── tree-leaf.jsx │ │ │ ├── tree.config.yml │ │ │ └── tree.spec.js │ │ └── wrapper │ │ │ ├── __snapshots__ │ │ │ └── wrapper.spec.js.snap │ │ │ ├── wrapper-consumer │ │ │ └── wrapper-consumer.jsx │ │ │ ├── wrapper-provider │ │ │ └── wrapper-provider.jsx │ │ │ └── wrapper.spec.js │ ├── fractal.config.js │ └── package.json └── twig │ ├── CHANGELOG.md │ ├── README.md │ ├── components │ ├── collated │ │ ├── __snapshots__ │ │ │ └── collated.spec.js.snap │ │ ├── collated.config.js │ │ ├── collated.spec.js │ │ └── collated.twig │ ├── components.spec.js │ ├── context │ │ ├── __snapshots__ │ │ │ └── context.spec.js.snap │ │ ├── async │ │ │ ├── async.config.js │ │ │ └── async.twig │ │ ├── context.spec.js │ │ ├── js │ │ │ ├── js.config.js │ │ │ └── js.twig │ │ ├── json │ │ │ ├── json.config.json │ │ │ └── json.twig │ │ ├── reference-full │ │ │ ├── reference-full.config.yml │ │ │ └── reference-full.twig │ │ ├── reference-key │ │ │ ├── reference-key.config.yml │ │ │ └── reference-key.twig │ │ ├── reference │ │ │ ├── reference.config.yml │ │ │ └── reference.twig │ │ └── yaml │ │ │ ├── yaml.config.yml │ │ │ └── yaml.twig │ ├── include │ │ ├── __snapshots__ │ │ │ └── include.spec.js.snap │ │ ├── include-child │ │ │ └── include-child.twig │ │ ├── include-parent │ │ │ ├── include-parent--self.twig │ │ │ └── include-parent.twig │ │ └── include.spec.js │ ├── notes │ │ ├── notes-config │ │ │ ├── notes-config.config.yml │ │ │ └── notes-config.twig │ │ ├── notes-files │ │ │ ├── notes-files--alt.readme.md │ │ │ ├── notes-files--alt.twig │ │ │ ├── notes-files.readme.md │ │ │ └── notes-files.twig │ │ └── notes.spec.js │ ├── path │ │ ├── __snapshots__ │ │ │ └── path.spec.js.snap │ │ ├── path.spec.js │ │ └── path.twig │ ├── render-tag │ │ ├── comp-1.config.yml │ │ ├── comp-1.twig │ │ ├── comp-2--escaped-handle.twig │ │ ├── comp-2--missing-handle.twig │ │ ├── comp-2--no-context.twig │ │ ├── comp-2--variant.twig │ │ ├── comp-2--wrong-handle.twig │ │ ├── comp-2.config.yml │ │ ├── comp-2.twig │ │ ├── config.yml │ │ ├── escaped-handle.config.yml │ │ ├── escaped-handle.twig │ │ └── render-tag.spec.js │ ├── render │ │ ├── __snapshots__ │ │ │ └── render.spec.js.snap │ │ ├── render--camelCaseVariant.twig │ │ ├── render--variant-2.twig │ │ ├── render.config.yml │ │ ├── render.spec.js │ │ └── render.twig │ ├── root │ │ ├── root-tree │ │ │ └── root-tree-leaf.twig │ │ └── root.config.yml │ └── tree │ │ ├── subtree │ │ ├── subtree-leaf │ │ │ ├── subtree-leaf--variant.twig │ │ │ ├── subtree-leaf.config.yml │ │ │ └── subtree-leaf.twig │ │ └── subtree.config.yml │ │ ├── tree-leaf │ │ ├── tree-leaf--variant.twig │ │ ├── tree-leaf.config.yml │ │ └── tree-leaf.twig │ │ ├── tree.config.yml │ │ └── tree.spec.js │ ├── docs │ ├── 01-index.md │ ├── __snapshots__ │ │ └── docs.spec.js.snap │ └── docs.spec.js │ ├── fractal.config.js │ └── package.json ├── jest.config.js ├── lerna.json ├── package-lock.json ├── package.json ├── packages ├── core │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── adapter.js │ │ ├── array-stream.js │ │ ├── data.js │ │ ├── entities │ │ │ ├── collection.js │ │ │ ├── entity.js │ │ │ ├── index.js │ │ │ └── source.js │ │ ├── fs.js │ │ ├── highlighter.js │ │ ├── index.js │ │ ├── log.js │ │ ├── markdown.js │ │ ├── mixins │ │ │ ├── collection.js │ │ │ ├── configurable.js │ │ │ ├── emitter.js │ │ │ ├── entity.js │ │ │ ├── heritable.js │ │ │ ├── index.js │ │ │ ├── mix.js │ │ │ └── source.js │ │ ├── promise-stream.js │ │ ├── resolver.js │ │ ├── shell.js │ │ └── utils.js │ └── test │ │ ├── __mocks__ │ │ └── fractal.js │ │ ├── __snapshots__ │ │ └── markdown.spec.js.snap │ │ ├── entities │ │ ├── __snapshots__ │ │ │ └── source.spec.js.snap │ │ └── source.spec.js │ │ ├── markdown.spec.js │ │ ├── mixins │ │ ├── collection.spec.js │ │ ├── configurable.spec.js │ │ ├── emitter.spec.js │ │ └── heritable.spec.js │ │ ├── shell.spec.js │ │ └── utils.spec.js ├── fractal │ ├── CHANGELOG.md │ ├── README.md │ ├── bin │ │ └── fractal.js │ ├── config.js │ ├── package.json │ ├── src │ │ ├── api │ │ │ ├── assets │ │ │ │ ├── asset.js │ │ │ │ ├── collection.js │ │ │ │ ├── index.js │ │ │ │ ├── source-collection.js │ │ │ │ └── source.js │ │ │ ├── components │ │ │ │ ├── collection.js │ │ │ │ ├── component.js │ │ │ │ ├── index.js │ │ │ │ └── source.js │ │ │ ├── docs │ │ │ │ ├── collection.js │ │ │ │ ├── doc.js │ │ │ │ ├── index.js │ │ │ │ └── source.js │ │ │ ├── files │ │ │ │ ├── collection.js │ │ │ │ └── file.js │ │ │ └── variants │ │ │ │ ├── collection.js │ │ │ │ └── variant.js │ │ ├── cli │ │ │ ├── cli.js │ │ │ ├── commands │ │ │ │ ├── info.js │ │ │ │ ├── new.js │ │ │ │ ├── web.build.js │ │ │ │ └── web.start.js │ │ │ ├── console.js │ │ │ ├── index.js │ │ │ ├── notifier.js │ │ │ ├── theme.js │ │ │ └── themes │ │ │ │ └── default.js │ │ └── fractal.js │ ├── test │ │ ├── api │ │ │ └── components │ │ │ │ └── source.spec.js │ │ ├── cli │ │ │ └── cli.spec.js │ │ └── fractal.spec.js │ └── views │ │ └── cli │ │ └── new │ │ ├── components │ │ └── example │ │ │ ├── example.config.yml │ │ │ └── example.hbs │ │ ├── docs │ │ └── index.md │ │ └── fractal.hbs ├── handlebars │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── adapter.js │ │ ├── helpers │ │ ├── context-data.js │ │ ├── context.js │ │ ├── index.js │ │ ├── path.js │ │ ├── render.js │ │ └── view.js │ │ └── partials │ │ ├── index.js │ │ └── package.json ├── mandelbrot │ ├── .eslintrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── assets │ │ ├── favicon.ico │ │ ├── img │ │ │ ├── favicon.png │ │ │ ├── icon-drag--horizontal.svg │ │ │ ├── icon-drag--vertical.svg │ │ │ ├── icon-navigation-closed-ltr.svg │ │ │ ├── icon-navigation-closed-rtl.svg │ │ │ ├── icon-navigation-opened.svg │ │ │ ├── icon-window.svg │ │ │ └── loader.svg │ │ ├── js │ │ │ ├── components │ │ │ │ ├── browser.js │ │ │ │ ├── frame.js │ │ │ │ ├── navigation.js │ │ │ │ ├── pen.js │ │ │ │ ├── preview.js │ │ │ │ ├── search.js │ │ │ │ └── tree.js │ │ │ ├── config.js │ │ │ ├── events.js │ │ │ ├── mandelbrot.js │ │ │ ├── storage.js │ │ │ └── utils.js │ │ └── scss │ │ │ ├── components │ │ │ ├── _all.scss │ │ │ ├── _asset-list.scss │ │ │ ├── _browser.scss │ │ │ ├── _code.scss │ │ │ ├── _document.scss │ │ │ ├── _error.scss │ │ │ ├── _file-browser.scss │ │ │ ├── _frame.scss │ │ │ ├── _header.scss │ │ │ ├── _meta.scss │ │ │ ├── _navigation.scss │ │ │ ├── _pen.scss │ │ │ ├── _preview.scss │ │ │ ├── _prose.scss │ │ │ ├── _search.scss │ │ │ ├── _status.scss │ │ │ └── _tree.scss │ │ │ ├── core │ │ │ ├── _all.scss │ │ │ ├── _foundation.scss │ │ │ └── _mixins.scss │ │ │ ├── highlight.scss │ │ │ ├── skins │ │ │ ├── aqua.scss │ │ │ ├── black.scss │ │ │ ├── blue.scss │ │ │ ├── default.scss │ │ │ ├── fuchsia.scss │ │ │ ├── green.scss │ │ │ ├── grey.scss │ │ │ ├── lime.scss │ │ │ ├── maroon.scss │ │ │ ├── navy.scss │ │ │ ├── olive.scss │ │ │ ├── orange.scss │ │ │ ├── purple.scss │ │ │ ├── red.scss │ │ │ ├── teal.scss │ │ │ ├── white.scss │ │ │ └── yellow.scss │ │ │ └── theme.scss │ ├── index.js │ ├── package.json │ ├── src │ │ ├── filters.js │ │ └── theme.js │ ├── views │ │ ├── icons │ │ │ ├── arrow-left.svg │ │ │ ├── asset.svg │ │ │ ├── burger.svg │ │ │ ├── close.svg │ │ │ ├── collapse.svg │ │ │ └── open-in-browser.svg │ │ ├── layouts │ │ │ ├── doc.nunj │ │ │ ├── frame.nunj │ │ │ ├── full.nunj │ │ │ ├── pen.nunj │ │ │ ├── pjax.nunj │ │ │ ├── render.nunj │ │ │ └── skeleton.nunj │ │ ├── macros │ │ │ ├── errors.nunj │ │ │ ├── image.nunj │ │ │ ├── navigation.nunj │ │ │ ├── render.nunj │ │ │ └── status.nunj │ │ ├── pages │ │ │ ├── assets.nunj │ │ │ ├── components │ │ │ │ ├── detail.nunj │ │ │ │ ├── preview.nunj │ │ │ │ └── render.nunj │ │ │ ├── doc.nunj │ │ │ └── error.nunj │ │ └── partials │ │ │ ├── browser │ │ │ ├── browser.nunj │ │ │ ├── controls.nunj │ │ │ ├── panel-context.nunj │ │ │ ├── panel-html.nunj │ │ │ ├── panel-info.nunj │ │ │ ├── panel-notes.nunj │ │ │ ├── panel-resources.nunj │ │ │ └── panel-view.nunj │ │ │ ├── content │ │ │ └── overview.nunj │ │ │ ├── foot.nunj │ │ │ ├── head.nunj │ │ │ ├── header.nunj │ │ │ ├── navigation │ │ │ ├── assets.nunj │ │ │ ├── components.nunj │ │ │ ├── docs.nunj │ │ │ ├── information.nunj │ │ │ ├── navigation.nunj │ │ │ ├── search.nunj │ │ │ └── variants.nunj │ │ │ ├── pen │ │ │ ├── browser.nunj │ │ │ ├── header.nunj │ │ │ └── preview.nunj │ │ │ ├── scripts.nunj │ │ │ └── stylesheets.nunj │ └── webpack.config.js ├── nunjucks │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── adapter.js │ │ ├── extensions │ │ ├── context.js │ │ ├── index.js │ │ ├── render.js │ │ └── view.js │ │ └── filters │ │ ├── index.js │ │ └── path.js ├── react │ ├── CHANGELOG.md │ ├── README.md │ ├── components │ │ ├── index.d.ts │ │ ├── index.js │ │ └── path-provider.js │ ├── index.js │ ├── package.json │ └── src │ │ ├── adapter.js │ │ └── clear-module.js ├── twig │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ ├── package.json │ └── src │ │ ├── adapter.js │ │ ├── filters │ │ ├── index.js │ │ └── path.js │ │ ├── functions │ │ ├── index.js │ │ └── package.json │ │ ├── tags │ │ ├── index.js │ │ └── render.js │ │ ├── tests │ │ ├── index.js │ │ └── package.json │ │ └── utils.js └── web │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ ├── builder.js │ ├── engine │ │ ├── engine.js │ │ ├── extensions │ │ │ └── .gitkeep │ │ ├── filters │ │ │ ├── async.js │ │ │ ├── format.js │ │ │ ├── highlight.js │ │ │ ├── is-error.js │ │ │ ├── markdown.js │ │ │ └── render.js │ │ ├── globals │ │ │ ├── dump.js │ │ │ ├── log.js │ │ │ ├── path.js │ │ │ ├── static.js │ │ │ └── throw.js │ │ └── index.js │ ├── error.js │ ├── index.js │ ├── server.js │ ├── theme.js │ └── web.js │ ├── test │ ├── server.spec.js │ ├── theme.spec.js │ └── web.spec.js │ └── views │ └── __system │ ├── error.nunj │ ├── index.nunj │ ├── redirect.nunj │ └── skeleton.nunj ├── prettier.config.js └── tests └── setup.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{*.{json,md,yml},.*rc}] 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 2018, 5 | }, 6 | extends: ['eslint:recommended', 'plugin:prettier/recommended', 'plugin:import/recommended'], 7 | env: { 8 | browser: true, 9 | node: true, 10 | es6: true, 11 | jest: true, 12 | }, 13 | plugins: ['import'], 14 | rules: { 15 | 'import/no-unresolved': [ 16 | 'error', 17 | { 18 | commonjs: true, 19 | }, 20 | ], 21 | 'import/no-extraneous-dependencies': 'error', 22 | }, 23 | overrides: [ 24 | { 25 | files: ['*.spec.js'], 26 | env: { 27 | jest: true, 28 | }, 29 | }, 30 | { 31 | files: ['**/*.jsx'], 32 | extends: ['plugin:react/recommended'], 33 | settings: { 34 | react: { 35 | version: 'detect', 36 | }, 37 | }, 38 | parserOptions: { 39 | ecmaFeatures: { jsx: true }, 40 | }, 41 | }, 42 | ], 43 | }; 44 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.png binary 3 | *.woff binary 4 | *.woff2 binary 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Use this template to report bugs 4 | labels: bug, needs-triage 5 | --- 6 | 7 | 12 | 13 | ### Steps to reproduce the issue 14 | 15 | 1. 16 | 2. 17 | 3. 18 | 19 | **Reproduces how often:** 20 | 21 | 22 | 23 | ### Reduced test case 24 | 25 | 26 | 27 | ### Context 28 | 29 | - Fractal version: 30 | - Node version: 31 | - OS: 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Questions & Support 4 | url: https://discord.gg/vuRz4Yx 5 | about: Please ask questions on our Discord server 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Use this template to request new features 4 | labels: feature-request, needs-triage 5 | --- 6 | 7 | 12 | 13 | ### What problem would this feature solve? 14 | 15 | 16 | 17 | ### What the feature should look like? 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable version updates for npm 4 | - package-ecosystem: "npm" 5 | # Look for `package.json` and `lock` files in the `root` directory 6 | directory: "/" 7 | # Check the npm registry for updates every day (weekdays) 8 | schedule: 9 | interval: "daily" 10 | versioning-strategy: "increase" 11 | - package-ecosystem: "github-actions" 12 | directory: "/" 13 | schedule: 14 | # Check for updates to GitHub Actions every weekday 15 | interval: "daily" 16 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: workflow_dispatch 3 | jobs: 4 | release: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2.4.0 8 | with: 9 | fetch-depth: '0' 10 | token: ${{ secrets.ADMIN_TOKEN }} 11 | - uses: actions/setup-node@v2.5.1 12 | with: 13 | node-version: 12 14 | registry-url: 'https://registry.npmjs.org' 15 | - run: git config user.name github-actions 16 | - run: git config user.email github-actions@github.com 17 | - run: npm ci 18 | - run: npm run bootstrap 19 | - run: npx lerna version --conventional-commits --create-release github --yes 20 | env: 21 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | - run: npx lerna publish from-git --yes --no-verify-access 23 | env: 24 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | jobs: 10 | test: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, windows-latest] 15 | node: [10, 12, 14, 16] 16 | steps: 17 | - uses: actions/checkout@v2.4.0 18 | - name: Use Node.js ${{ matrix.node }} 19 | uses: actions/setup-node@v2.5.1 20 | with: 21 | node-version: ${{ matrix.node }} 22 | - run: npm ci 23 | - run: npm run bootstrap 24 | - run: npm test 25 | env: 26 | CI: true 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | coverage 4 | dist 5 | /example/* 6 | /build/* 7 | /fractal.js 8 | .idea/ 9 | .eslintcache 10 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['stylelint-config-standard', 'stylelint-config-prettier'], 3 | plugins: ['stylelint-scss', 'stylelint-prettier'], 4 | rules: { 5 | 'prettier/prettier': true, 6 | indentation: 4, 7 | 'at-rule-no-unknown': null, 8 | 'scss/at-rule-no-unknown': true, 9 | 'no-descending-specificity': null, 10 | 'font-family-no-missing-generic-family-keyword': null, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Mark Perkins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // for running react example tests 3 | presets: ['@babel/preset-react', '@babel/preset-env'], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Fractal examples 2 | 3 | This folder contains examples of Fractal instances using various adapters & settings. 4 | 5 | Although we use them for developing and testing Fractal, they are probably a great resource for users as well. 6 | -------------------------------------------------------------------------------- /examples/adapter-tests/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [0.2.0](https://github.com/frctl/fractal/compare/@frctl/adapter-tests@0.1.0...@frctl/adapter-tests@0.2.0) (2021-02-14) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * **handlebars:** fix render tag resolving escaped component handles to context object ([#884](https://github.com/frctl/fractal/issues/884)) ([467d942](https://github.com/frctl/fractal/commit/467d942f089d81b955e4ce514d3c69bd1ce9c177)) 12 | 13 | 14 | ### Features 15 | 16 | * **react:** add PathProvider helper component ([#861](https://github.com/frctl/fractal/issues/861)) ([e947d3a](https://github.com/frctl/fractal/commit/e947d3a030e5d1dcfdd94013d6ee2278ed7ea93c)) 17 | 18 | 19 | 20 | 21 | 22 | # 0.1.0 (2021-02-07) 23 | 24 | 25 | ### Features 26 | 27 | * add react adapter ([#840](https://github.com/frctl/fractal/issues/840)) ([3d30579](https://github.com/frctl/fractal/commit/3d30579c99c14872420d43d834f04bcb7f36fb94)) 28 | -------------------------------------------------------------------------------- /examples/adapter-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/adapter-tests", 3 | "version": "0.2.0", 4 | "private": true, 5 | "main": "src/index.js" 6 | } 7 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/collated.js: -------------------------------------------------------------------------------- 1 | module.exports = function collated(fractal) { 2 | it('renders collated components collated', async () => { 3 | const render = await fractal.components.find('@collated').render(null, null, { collate: true }); 4 | expect(render).toMatchSnapshot(); 5 | }); 6 | }; 7 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/components.js: -------------------------------------------------------------------------------- 1 | module.exports = function components(fractal) { 2 | it('properly loads components', () => { 3 | expect(fractal.components.find('@tree-leaf')).toBeDefined(); 4 | expect(fractal.components.find('@subtree-leaf')).toBeDefined(); 5 | }); 6 | 7 | it('properly loads variants from files', () => { 8 | expect(fractal.components.find('@tree-leaf--variant')).toBeDefined(); 9 | expect(fractal.components.find('@subtree-leaf--variant')).toBeDefined(); 10 | }); 11 | 12 | it('properly loads variants from config', () => { 13 | expect(fractal.components.find('@tree-leaf--another')).toBeDefined(); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/docs.js: -------------------------------------------------------------------------------- 1 | module.exports = function docs(fractal) { 2 | it('properly loads docs', () => { 3 | expect(fractal.docs.find('@index')).toBeDefined(); 4 | }); 5 | 6 | it('properly loads docs front-matter', () => { 7 | expect(fractal.docs.find('@index').title).toBe('Project Overview'); 8 | }); 9 | 10 | it('properly render docs through templating engine', async () => { 11 | const render = await fractal.docs.find('@index').render(); 12 | expect(render).toMatchSnapshot(); 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/include.js: -------------------------------------------------------------------------------- 1 | module.exports = function include(fractal) { 2 | it('includes child component', async () => { 3 | const render = await fractal.components.find('@include-parent').render(); 4 | expect(render).toMatchSnapshot(); 5 | }); 6 | 7 | it('does not modify _self when including child component', async () => { 8 | const render = await fractal.components.find('@include-parent--self').render(); 9 | expect(render).toMatchSnapshot(); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports.components = require('./components'); 2 | module.exports.tree = require('./tree'); 3 | module.exports.renderTag = require('./render-tag'); 4 | module.exports.docs = require('./docs'); 5 | module.exports.render = require('./render'); 6 | module.exports.notes = require('./notes'); 7 | module.exports.include = require('./include'); 8 | module.exports.context = require('./context'); 9 | module.exports.collated = require('./collated'); 10 | module.exports.path = require('./path'); 11 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/notes.js: -------------------------------------------------------------------------------- 1 | module.exports = function notes(fractal) { 2 | it('loads notes from config', async () => { 3 | const cmp = await fractal.components.find('@notes-config'); 4 | expect(cmp.notes).toBe('Component Notes'); 5 | }); 6 | 7 | it('loads notes from config for variants', async () => { 8 | const cmp = await fractal.components.find('@notes-config--alt'); 9 | expect(cmp.notes).toBe('Component Notes for variant'); 10 | }); 11 | 12 | it('loads notes from readme file', async () => { 13 | const cmp = await fractal.components.find('@notes-files'); 14 | expect(cmp.notes).toBe('Component Notes\n'); 15 | }); 16 | 17 | it('loads notes from readme file for variants', async () => { 18 | const cmp = await fractal.components.find('@notes-files--alt'); 19 | expect(cmp.notes).toBe('Component Notes for variant\n'); 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/path.js: -------------------------------------------------------------------------------- 1 | module.exports = function path(fractal) { 2 | it('renders original path for server', async () => { 3 | const render = await fractal.components.find('@path').render(undefined, { server: true }); 4 | expect(render).toMatchSnapshot(); 5 | }); 6 | 7 | it('converts absolute path to relative for builder', async () => { 8 | const render = await fractal.components.find('@path').render(undefined, { builder: true }); 9 | expect(render).toMatchSnapshot(); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/render.js: -------------------------------------------------------------------------------- 1 | module.exports = function render(fractal) { 2 | it('renders default template for default variant', async () => { 3 | const render = await fractal.components.find('@render').render(); 4 | expect(render).toMatchSnapshot(); 5 | }); 6 | 7 | it('renders default template for regular variant', async () => { 8 | const render = await fractal.components.find('@render--variant-1').render(); 9 | expect(render).toMatchSnapshot(); 10 | }); 11 | 12 | it('renders variant template for variant with the same name', async () => { 13 | const render = await fractal.components.find('@render--variant-2').render(); 14 | expect(render).toMatchSnapshot(); 15 | }); 16 | 17 | it('renders specified template for variant', async () => { 18 | const render = await fractal.components.find('@render--variant-3').render(); 19 | expect(render).toMatchSnapshot(); 20 | }); 21 | 22 | it('renders specified camelCased template for variant', async () => { 23 | const render = await fractal.components.find('@render--variant-4').render(); 24 | expect(render).toMatchSnapshot(); 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /examples/adapter-tests/src/tree.js: -------------------------------------------------------------------------------- 1 | module.exports = function tree(fractal) { 2 | it('inherits context from parents', () => { 3 | expect(fractal.components.find('@subtree-leaf').context.root).toBe(true); 4 | expect(fractal.components.find('@subtree-leaf').context.subTree).toBe(true); 5 | expect(fractal.components.find('@subtree-leaf').context.subTreeLeaf).toBe(true); 6 | }); 7 | 8 | it('overrides context from parents', () => { 9 | expect(fractal.components.find('@tree-leaf--another').context.level).toBe(2); 10 | }); 11 | 12 | it('overrides context from parents and pass it further down', () => { 13 | expect(fractal.components.find('@subtree-leaf').context.level).toBe(2); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /examples/handlebars/README.md: -------------------------------------------------------------------------------- 1 | # Fractal Handlebars example 2 | 3 | This is an example instance of Fractal using the default Handlebars adapter. 4 | 5 | ## Setup 6 | 7 | [Follow these instructions](https://github.com/frctl/fractal#development) to setup the development environement, then run: 8 | 9 | ```bash 10 | npm start 11 | ``` 12 | 13 | to start Fractal server in development mode, or: 14 | 15 | ``` 16 | npm run build 17 | ``` 18 | 19 | to build a static version in the `dist` folder. 20 | 21 | ## Tests 22 | 23 | Run tests from root directory. 24 | -------------------------------------------------------------------------------- /examples/handlebars/components/collated/__snapshots__/collated.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`collated renders collated components collated 1`] = ` 4 | " 5 |
6 | Collated component default 7 |
8 | 9 | 10 | 11 |
12 | Collated component one 13 |
14 | 15 | 16 | 17 |
18 | Collated component two 19 |
20 | 21 | 22 | 23 |
24 | Collated component three 25 |
26 | 27 | " 28 | `; 29 | -------------------------------------------------------------------------------- /examples/handlebars/components/collated/collated.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collated: true, 3 | variants: [ 4 | { 5 | context: { 6 | foo: 'bar', 7 | }, 8 | name: 'one', 9 | }, 10 | { 11 | name: 'two', 12 | }, 13 | { 14 | name: 'three', 15 | }, 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /examples/handlebars/components/collated/collated.hbs: -------------------------------------------------------------------------------- 1 |
2 | Collated component {{ _self.name }} 3 |
4 | -------------------------------------------------------------------------------- /examples/handlebars/components/collated/collated.spec.js: -------------------------------------------------------------------------------- 1 | const { collated } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('collated', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | collated(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/components.spec.js: -------------------------------------------------------------------------------- 1 | const { components } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../fractal.config.js'); 4 | 5 | describe('components', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | components(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/context-data/a.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | items: 3 | - '@context-data-b' 4 | -------------------------------------------------------------------------------- /examples/handlebars/components/context-data/a.hbs: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/handlebars/components/context-data/b.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | foo: bar 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/context-data/b.hbs: -------------------------------------------------------------------------------- 1 |
  • {{ foo }}
  • 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/context-data/config.yml: -------------------------------------------------------------------------------- 1 | prefix: context-data 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/context-data/context-data.spec.js: -------------------------------------------------------------------------------- 1 | const fractal = require('../../fractal.config.js'); 2 | 3 | describe('context-data', () => { 4 | beforeEach(async () => { 5 | await fractal.load(); 6 | }); 7 | 8 | it('does not modify used component context', async () => { 9 | const correctContext = { items: [{ foo: 'bar' }] }; 10 | const initialContext = await fractal.components.find('@context-data-a').variants().default().getContext(); 11 | expect(initialContext).toEqual(correctContext); 12 | await fractal.components.find('@context-data-a').render(); 13 | const context = await fractal.components.find('@context-data-a').variants().default().getContext(); 14 | expect(context).toEqual(correctContext); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/__snapshots__/context.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`tree asynchronously loads context 1`] = ` 4 | Object { 5 | "xkcd": Object { 6 | "alt": "Proper User Policy apparently means Simon Says.", 7 | "day": "28", 8 | "img": "https://imgs.xkcd.com/comics/sandwich.png", 9 | "link": "", 10 | "month": "8", 11 | "news": "", 12 | "num": 149, 13 | "safe_title": "Sandwich", 14 | "title": "Sandwich", 15 | "transcript": "[[ A man is sitting on a couch, talking to another man. They are both stick figures. ]] 16 | First man: Make me a sandwich. 17 | Second man: What? Make it yourself. 18 | First man: Sudo make me a sandwich. 19 | Second man: Okay", 20 | "year": "2006", 21 | }, 22 | } 23 | `; 24 | 25 | exports[`tree loads fully rendered component from another component context key 1`] = ` 26 | "

    JS Context

    27 | " 28 | `; 29 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/async/async.config.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | const response = fetch('https://xkcd.com/149/info.0.json').then((response) => response.json()); 4 | 5 | module.exports = { 6 | context: { 7 | xkcd: response, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/async/async.hbs: -------------------------------------------------------------------------------- 1 | 2 | {{ xkcd.title }} 3 | 4 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/context.spec.js: -------------------------------------------------------------------------------- 1 | const { context } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('tree', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | context(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/js/js.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | context: { 3 | text: 'JS Context', 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/js/js.hbs: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/json/json.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "context": { 3 | "text": "JSON Context" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/json/json.hbs: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/reference-full/reference-full.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | reference: '@@reference' 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/reference-full/reference-full.hbs: -------------------------------------------------------------------------------- 1 |
    {{ reference }}
    2 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/reference-key/reference-key.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: '@js.text' 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/reference-key/reference-key.hbs: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/reference/reference.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | parent: '@js' 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/reference/reference.hbs: -------------------------------------------------------------------------------- 1 |

    {{ parent.text }}

    2 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/yaml/yaml.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: YAML Context 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/context/yaml/yaml.hbs: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/handlebars/components/include/__snapshots__/include.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`include does not modify _self when including child component 1`] = ` 4 | "include-parent--self 5 | include child 6 | include-parent--self 7 | " 8 | `; 9 | 10 | exports[`include includes child component 1`] = ` 11 | "include parent 12 | include child 13 | " 14 | `; 15 | -------------------------------------------------------------------------------- /examples/handlebars/components/include/include-child/include-child.hbs: -------------------------------------------------------------------------------- 1 | include child 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/include/include-parent/include-parent--self.hbs: -------------------------------------------------------------------------------- 1 | {{ _self.handle }} 2 | {{> @include-child }} 3 | {{ _self.handle }} 4 | -------------------------------------------------------------------------------- /examples/handlebars/components/include/include-parent/include-parent.hbs: -------------------------------------------------------------------------------- 1 | include parent 2 | {{> @include-child }} 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/include/include.spec.js: -------------------------------------------------------------------------------- 1 | const { include } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('include', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | include(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/notes/notes-config/notes-config.config.yml: -------------------------------------------------------------------------------- 1 | notes: Component Notes 2 | variants: 3 | - name: alt 4 | notes: Component Notes for variant 5 | -------------------------------------------------------------------------------- /examples/handlebars/components/notes/notes-config/notes-config.hbs: -------------------------------------------------------------------------------- 1 | Load notes from config 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/notes/notes-files/notes-files--alt.hbs: -------------------------------------------------------------------------------- 1 | Load notes from readme files 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/notes/notes-files/notes-files--alt.readme.md: -------------------------------------------------------------------------------- 1 | Component Notes for variant 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/notes/notes-files/notes-files.hbs: -------------------------------------------------------------------------------- 1 | Load notes from readme files 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/notes/notes-files/notes-files.readme.md: -------------------------------------------------------------------------------- 1 | Component Notes 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/notes/notes.spec.js: -------------------------------------------------------------------------------- 1 | const { notes } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('notes', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | notes(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/one-very-very-long-component-name.hbs: -------------------------------------------------------------------------------- 1 | A component with a very long name. 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/partial-block/config.yml: -------------------------------------------------------------------------------- 1 | prefix: partial-block 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/partial-block/parent.hbs: -------------------------------------------------------------------------------- 1 | {{#> @partial-block-partial }} 2 | parent 3 | {{/@partial-block-partial }} 4 | -------------------------------------------------------------------------------- /examples/handlebars/components/partial-block/partial-block.spec.js: -------------------------------------------------------------------------------- 1 | const fractal = require('../../fractal.config.js'); 2 | 3 | describe('partial-block', () => { 4 | beforeEach(async () => { 5 | await fractal.load(); 6 | }); 7 | 8 | it('properly loads components', () => { 9 | expect(fractal.components.find('@partial-block-partial')).toBeDefined(); 10 | expect(fractal.components.find('@partial-block-parent')).toBeDefined(); 11 | }); 12 | 13 | it('renders partial', async () => { 14 | const render = await fractal.components.find('@partial-block-partial').render(); 15 | expect(render).toBe('partial\n \n'); 16 | }); 17 | 18 | it('renders parent', async () => { 19 | const render = await fractal.components.find('@partial-block-parent').render(); 20 | expect(render).toBe('partial\n parent\n'); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /examples/handlebars/components/partial-block/partial.hbs: -------------------------------------------------------------------------------- 1 | partial 2 | {{#> @partial-block}} 3 | {{content}} 4 | {{/ @partial-block}} 5 | -------------------------------------------------------------------------------- /examples/handlebars/components/path/__snapshots__/path.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`path converts absolute path to relative for builder 1`] = ` 4 | "./some-path.html 5 | " 6 | `; 7 | 8 | exports[`path renders original path for server 1`] = ` 9 | "/some-path 10 | " 11 | `; 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/path/path.hbs: -------------------------------------------------------------------------------- 1 | {{path '/some-path' }} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/path/path.spec.js: -------------------------------------------------------------------------------- 1 | const { path } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('path', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | path(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-1.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: Default Context 3 | container: 4 | text: Default Context 5 | variants: 6 | - name: variant 7 | context: 8 | text: Variant Context 9 | container: 10 | text: Variant Context 11 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-1.hbs: -------------------------------------------------------------------------------- 1 | {{ container.text }} 2 | {{ text }} 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-2--escaped-handle.hbs: -------------------------------------------------------------------------------- 1 | {{render "@render-tag-escaped-handle"}} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-2--missing-handle.hbs: -------------------------------------------------------------------------------- 1 | {{render "@render-tag-comp-3"}} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-2--no-context.hbs: -------------------------------------------------------------------------------- 1 | {{render "@render-tag-comp-1"}} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-2--variant.hbs: -------------------------------------------------------------------------------- 1 | {{render "@render-tag-comp-1--variant" newContext merge=true}} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-2--wrong-handle.hbs: -------------------------------------------------------------------------------- 1 | {{render "render-tag-comp-1"}} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-2.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | newContext: 3 | container: 4 | text: Override Context 5 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/comp-2.hbs: -------------------------------------------------------------------------------- 1 | {{render "@render-tag-comp-1" newContext merge=true}} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/config.yml: -------------------------------------------------------------------------------- 1 | prefix: render-tag 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/escaped-handle.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | handle: '\@render-tag-comp-1' 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/escaped-handle.hbs: -------------------------------------------------------------------------------- 1 | {{ handle }} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render-tag/render-tag.spec.js: -------------------------------------------------------------------------------- 1 | const { renderTag } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('render-tag', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | renderTag(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/render/__snapshots__/render.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`render renders default template for default variant 1`] = ` 4 | "Render something 5 | " 6 | `; 7 | 8 | exports[`render renders default template for regular variant 1`] = ` 9 | "Render variant-1 10 | " 11 | `; 12 | 13 | exports[`render renders specified camelCased template for variant 1`] = ` 14 | "Render camelCaseVariant something 15 | " 16 | `; 17 | 18 | exports[`render renders specified template for variant 1`] = ` 19 | "Render variant-2 something 20 | " 21 | `; 22 | 23 | exports[`render renders variant template for variant with the same name 1`] = ` 24 | "Render variant-2 something 25 | " 26 | `; 27 | -------------------------------------------------------------------------------- /examples/handlebars/components/render/render--camelCaseVariant.hbs: -------------------------------------------------------------------------------- 1 | Render camelCaseVariant {{ something }} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render/render--variant-2.hbs: -------------------------------------------------------------------------------- 1 | Render variant-2 {{ something }} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render/render.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | something: something 3 | variants: 4 | - name: variant-1 5 | context: 6 | something: variant-1 7 | - name: variant-2 8 | - name: variant-3 9 | view: render--variant-2.hbs 10 | - name: variant-4 11 | view: render--camelCaseVariant.hbs 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/render/render.hbs: -------------------------------------------------------------------------------- 1 | Render {{ something }} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/render/render.spec.js: -------------------------------------------------------------------------------- 1 | const { render } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('render', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | render(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/components/root/root-tree/root-tree-leaf.hbs: -------------------------------------------------------------------------------- 1 | root tree leaf 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/root/root.config.yml: -------------------------------------------------------------------------------- 1 | root: true 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/subtree/subtree-leaf/subtree-leaf--variant.hbs: -------------------------------------------------------------------------------- 1 | Subtree leaf variant 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/subtree/subtree-leaf/subtree-leaf.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | subTreeLeaf: true 3 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/subtree/subtree-leaf/subtree-leaf.hbs: -------------------------------------------------------------------------------- 1 | Subtree leaf 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/subtree/subtree.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | level: 2 3 | subTree: true 4 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/tree-leaf/tree-leaf--variant.hbs: -------------------------------------------------------------------------------- 1 | Tree leaf variant 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/tree-leaf/tree-leaf.config.yml: -------------------------------------------------------------------------------- 1 | variants: 2 | - name: another 3 | context: 4 | level: 2 5 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/tree-leaf/tree-leaf.hbs: -------------------------------------------------------------------------------- 1 | Tree leaf {{ _self.name }} 2 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/tree.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | level: 1 3 | root: true 4 | -------------------------------------------------------------------------------- /examples/handlebars/components/tree/tree.spec.js: -------------------------------------------------------------------------------- 1 | const { tree } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('tree', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | tree(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/docs/01-index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Project Overview 3 | context: 4 | items: 5 | - Finish the docs 6 | - Write tests 7 | - Make the tea 8 | --- 9 | 10 | This is some documentation for the project. Still to do: 11 | 12 | {{#each items}} 13 | 14 | - {{ this }} 15 | {{/each}} 16 | -------------------------------------------------------------------------------- /examples/handlebars/docs/__snapshots__/docs.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`docs properly render docs through templating engine 1`] = ` 4 | "

    This is some documentation for the project. Still to do:

    5 | 13 | " 14 | `; 15 | -------------------------------------------------------------------------------- /examples/handlebars/docs/docs.spec.js: -------------------------------------------------------------------------------- 1 | const { docs } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../fractal.config.js'); 4 | 5 | describe('docs', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | docs(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/handlebars/fractal.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | * Require the path module 5 | */ 6 | const path = require('path'); 7 | const mandelbrot = require('@frctl/mandelbrot'); 8 | 9 | /* 10 | * Require the Fractal module 11 | */ 12 | const fractal = (module.exports = require('@frctl/fractal').create()); 13 | 14 | /* 15 | * Give your project a title. 16 | */ 17 | fractal.set('project.title', 'Fractal Handlebars example'); 18 | 19 | /* 20 | * Tell Fractal where to look for components. 21 | */ 22 | fractal.components.set('path', path.join(__dirname, 'components')); 23 | 24 | /* 25 | * Tell Fractal where to look for documentation pages. 26 | */ 27 | fractal.docs.set('path', path.join(__dirname, 'docs')); 28 | 29 | /* 30 | * Tell the Fractal web preview plugin where to look for static assets. 31 | */ 32 | fractal.web.set('static.path', path.join(__dirname, 'public')); 33 | 34 | /* 35 | * Tell the Fractal where to output the build files. 36 | */ 37 | fractal.web.set('builder.dest', path.join(__dirname, 'dist')); 38 | 39 | /* 40 | * Customize Mandelbrot 41 | */ 42 | const customTheme = mandelbrot({ 43 | // See https://fractal.build/guide/web/default-theme.html#configuration 44 | }); 45 | 46 | fractal.web.theme(customTheme); 47 | -------------------------------------------------------------------------------- /examples/handlebars/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/handlebars-example", 3 | "version": "0.3.12", 4 | "private": true, 5 | "scripts": { 6 | "start": "fractal start --sync", 7 | "build": "fractal build" 8 | }, 9 | "dependencies": { 10 | "@frctl/fractal": "^1.5.15", 11 | "@frctl/handlebars": "^1.2.15", 12 | "@frctl/mandelbrot": "^1.10.3" 13 | }, 14 | "devDependencies": { 15 | "@frctl/adapter-tests": "^0.2.0", 16 | "node-fetch": "^2.6.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/handlebars/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frctl/fractal/dd6cd938653b24cd23456d10b9c28d3bc436c4c3/examples/handlebars/public/.gitkeep -------------------------------------------------------------------------------- /examples/nunjucks/README.md: -------------------------------------------------------------------------------- 1 | # Fractal Nunjucks example 2 | 3 | This is an example instance of Fractal using the Nunjucks adapter. 4 | 5 | ## Setup 6 | 7 | [Follow these instructions](https://github.com/frctl/fractal#development) to setup the development environement, then run: 8 | 9 | ```bash 10 | npm start 11 | ``` 12 | 13 | to start Fractal server in development mode, or: 14 | 15 | ``` 16 | npm run build 17 | ``` 18 | 19 | to build a static version in the `dist` folder. 20 | 21 | ## Tests 22 | 23 | Run tests from root directory. 24 | -------------------------------------------------------------------------------- /examples/nunjucks/components/collated/__snapshots__/collated.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`collated renders collated components collated 1`] = ` 4 | " 5 |
    6 | Collated component default 7 |
    8 | 9 | 10 | 11 |
    12 | Collated component one 13 |
    14 | 15 | 16 | 17 |
    18 | Collated component two 19 |
    20 | 21 | 22 | 23 |
    24 | Collated component three 25 |
    26 | 27 | " 28 | `; 29 | -------------------------------------------------------------------------------- /examples/nunjucks/components/collated/collated.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collated: true, 3 | variants: [ 4 | { 5 | context: { 6 | foo: 'bar', 7 | }, 8 | name: 'one', 9 | }, 10 | { 11 | name: 'two', 12 | }, 13 | { 14 | name: 'three', 15 | }, 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /examples/nunjucks/components/collated/collated.njk: -------------------------------------------------------------------------------- 1 |
    2 | Collated component {{ _self.name }} 3 |
    4 | -------------------------------------------------------------------------------- /examples/nunjucks/components/collated/collated.spec.js: -------------------------------------------------------------------------------- 1 | const { collated } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('collated', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | collated(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/components.spec.js: -------------------------------------------------------------------------------- 1 | const { components } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../fractal.config.js'); 4 | 5 | describe('components', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | components(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/__snapshots__/context.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`context asynchronously loads context 1`] = ` 4 | Object { 5 | "xkcd": Object { 6 | "alt": "Proper User Policy apparently means Simon Says.", 7 | "day": "28", 8 | "img": "https://imgs.xkcd.com/comics/sandwich.png", 9 | "link": "", 10 | "month": "8", 11 | "news": "", 12 | "num": 149, 13 | "safe_title": "Sandwich", 14 | "title": "Sandwich", 15 | "transcript": "[[ A man is sitting on a couch, talking to another man. They are both stick figures. ]] 16 | First man: Make me a sandwich. 17 | Second man: What? Make it yourself. 18 | First man: Sudo make me a sandwich. 19 | Second man: Okay", 20 | "year": "2006", 21 | }, 22 | } 23 | `; 24 | 25 | exports[`context loads fully rendered component from another component context key 1`] = ` 26 | "

    JS Context

    27 | " 28 | `; 29 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/async/async.config.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | const response = fetch('https://xkcd.com/149/info.0.json').then((response) => response.json()); 4 | 5 | module.exports = { 6 | context: { 7 | xkcd: response, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/async/async.njk: -------------------------------------------------------------------------------- 1 | 2 | {{ xkcd.title }} 3 | 4 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/context.spec.js: -------------------------------------------------------------------------------- 1 | const { context } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('context', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | context(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/js/js.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | context: { 3 | text: 'JS Context', 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/js/js.njk: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/json/json.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "context": { 3 | "text": "JSON Context" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/json/json.njk: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/reference-full/reference-full.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | reference: '@@reference' 3 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/reference-full/reference-full.njk: -------------------------------------------------------------------------------- 1 |
    {{ reference }}
    2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/reference-key/reference-key.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: '@js.text' 3 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/reference-key/reference-key.njk: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/reference/reference.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | parent: '@js' 3 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/reference/reference.njk: -------------------------------------------------------------------------------- 1 |

    {{ parent.text }}

    2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/yaml/yaml.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: YAML Context 3 | -------------------------------------------------------------------------------- /examples/nunjucks/components/context/yaml/yaml.njk: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/include/__snapshots__/include.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`include does not modify _self when including child component 1`] = ` 4 | "include-parent--self 5 | include child 6 | 7 | include-parent--self 8 | " 9 | `; 10 | 11 | exports[`include includes child component 1`] = ` 12 | "include parent 13 | include child 14 | 15 | " 16 | `; 17 | -------------------------------------------------------------------------------- /examples/nunjucks/components/include/include-child/include-child.njk: -------------------------------------------------------------------------------- 1 | include child 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/include/include-parent/include-parent--self.njk: -------------------------------------------------------------------------------- 1 | {{ _self.handle }} 2 | {% include '@include-child' %} 3 | {{ _self.handle }} 4 | -------------------------------------------------------------------------------- /examples/nunjucks/components/include/include-parent/include-parent.njk: -------------------------------------------------------------------------------- 1 | include parent 2 | {% include '@include-child' %} 3 | -------------------------------------------------------------------------------- /examples/nunjucks/components/include/include.spec.js: -------------------------------------------------------------------------------- 1 | const { include } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('include', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | include(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/notes/notes-config/notes-config.config.yml: -------------------------------------------------------------------------------- 1 | notes: Component Notes 2 | variants: 3 | - name: alt 4 | notes: Component Notes for variant 5 | -------------------------------------------------------------------------------- /examples/nunjucks/components/notes/notes-config/notes-config.njk: -------------------------------------------------------------------------------- 1 | Load notes from config 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/notes/notes-files/notes-files--alt.njk: -------------------------------------------------------------------------------- 1 | Load notes from readme files 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/notes/notes-files/notes-files--alt.readme.md: -------------------------------------------------------------------------------- 1 | Component Notes for variant 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/notes/notes-files/notes-files.njk: -------------------------------------------------------------------------------- 1 | Load notes from readme files 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/notes/notes-files/notes-files.readme.md: -------------------------------------------------------------------------------- 1 | Component Notes 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/notes/notes.spec.js: -------------------------------------------------------------------------------- 1 | const { notes } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('notes', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | notes(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/path/__snapshots__/path.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`path converts absolute path to relative for builder 1`] = ` 4 | "./some-path.html 5 | " 6 | `; 7 | 8 | exports[`path renders original path for server 1`] = ` 9 | "/some-path 10 | " 11 | `; 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/path/path.njk: -------------------------------------------------------------------------------- 1 | {{ '/some-path' | path }} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/path/path.spec.js: -------------------------------------------------------------------------------- 1 | const { path } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('path', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | path(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-1.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: Default Context 3 | container: 4 | text: Default Context 5 | variants: 6 | - name: variant 7 | context: 8 | text: Variant Context 9 | container: 10 | text: Variant Context 11 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-1.njk: -------------------------------------------------------------------------------- 1 | {{ container.text }} 2 | {{ text }} 3 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-2--escaped-handle.njk: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-escaped-handle' %} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-2--missing-handle.njk: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-comp-3' %} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-2--no-context.njk: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-comp-1' %} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-2--variant.njk: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-comp-1--variant', newContext, true %} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-2--wrong-handle.njk: -------------------------------------------------------------------------------- 1 | {% render 'render-tag-comp-1' %} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-2.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | newContext: 3 | container: 4 | text: Override Context 5 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/comp-2.njk: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-comp-1', newContext, true %} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/config.yml: -------------------------------------------------------------------------------- 1 | prefix: render-tag 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/escaped-handle.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | handle: '\@render-tag-comp-1' 3 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/escaped-handle.njk: -------------------------------------------------------------------------------- 1 | {{ handle }} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render-tag/render-tag.spec.js: -------------------------------------------------------------------------------- 1 | const { renderTag } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('render-tag', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | renderTag(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render/__snapshots__/render.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`render renders default template for default variant 1`] = ` 4 | "Render something 5 | " 6 | `; 7 | 8 | exports[`render renders default template for regular variant 1`] = ` 9 | "Render variant-1 10 | " 11 | `; 12 | 13 | exports[`render renders specified camelCased template for variant 1`] = ` 14 | "Render camelCaseVariant something 15 | " 16 | `; 17 | 18 | exports[`render renders specified template for variant 1`] = ` 19 | "Render variant-2 something 20 | " 21 | `; 22 | 23 | exports[`render renders variant template for variant with the same name 1`] = ` 24 | "Render variant-2 something 25 | " 26 | `; 27 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render/render--camelCaseVariant.njk: -------------------------------------------------------------------------------- 1 | Render camelCaseVariant {{ something }} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render/render--variant-2.njk: -------------------------------------------------------------------------------- 1 | Render variant-2 {{ something }} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render/render.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | something: something 3 | variants: 4 | - name: variant-1 5 | context: 6 | something: variant-1 7 | - name: variant-2 8 | - name: variant-3 9 | view: render--variant-2.njk 10 | - name: variant-4 11 | view: render--camelCaseVariant.njk 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render/render.njk: -------------------------------------------------------------------------------- 1 | Render {{ something }} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/render/render.spec.js: -------------------------------------------------------------------------------- 1 | const { render } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('render', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | render(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/components/root/root-tree/root-tree-leaf.njk: -------------------------------------------------------------------------------- 1 | root tree leaf 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/root/root.config.yml: -------------------------------------------------------------------------------- 1 | root: true 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/subtree/subtree-leaf/subtree-leaf--variant.njk: -------------------------------------------------------------------------------- 1 | Subtree leaf variant 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/subtree/subtree-leaf/subtree-leaf.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | subTreeLeaf: true 3 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/subtree/subtree-leaf/subtree-leaf.njk: -------------------------------------------------------------------------------- 1 | Subtree leaf 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/subtree/subtree.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | level: 2 3 | subTree: true 4 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/tree-leaf/tree-leaf--variant.njk: -------------------------------------------------------------------------------- 1 | Tree leaf variant 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/tree-leaf/tree-leaf.config.yml: -------------------------------------------------------------------------------- 1 | variants: 2 | - name: another 3 | context: 4 | level: 2 5 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/tree-leaf/tree-leaf.njk: -------------------------------------------------------------------------------- 1 | Tree leaf {{ _self.name }} 2 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/tree.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | level: 1 3 | root: true 4 | -------------------------------------------------------------------------------- /examples/nunjucks/components/tree/tree.spec.js: -------------------------------------------------------------------------------- 1 | const { tree } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('tree', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | tree(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/docs/01-index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Project Overview 3 | context: 4 | items: 5 | - Finish the docs 6 | - Write tests 7 | - Make the tea 8 | --- 9 | 10 | This is some documentation for the project. Still to do: 11 | 12 | {% for item in items %} 13 | - {{ item }} 14 | {% endfor %} 15 | -------------------------------------------------------------------------------- /examples/nunjucks/docs/__snapshots__/docs.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`docs properly render docs through templating engine 1`] = ` 4 | "

    This is some documentation for the project. Still to do:

    5 | 13 | " 14 | `; 15 | -------------------------------------------------------------------------------- /examples/nunjucks/docs/docs.spec.js: -------------------------------------------------------------------------------- 1 | const { docs } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../fractal.config.js'); 4 | 5 | describe('docs', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | docs(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/nunjucks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/nunjucks-example", 3 | "version": "0.0.10", 4 | "private": true, 5 | "scripts": { 6 | "start": "fractal start --sync", 7 | "build": "fractal build" 8 | }, 9 | "dependencies": { 10 | "@frctl/fractal": "^1.5.15", 11 | "@frctl/mandelbrot": "^1.10.3", 12 | "@frctl/nunjucks": "^2.0.15" 13 | }, 14 | "devDependencies": { 15 | "@frctl/adapter-tests": "^0.1.0", 16 | "node-fetch": "^2.6.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/nunjucks/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frctl/fractal/dd6cd938653b24cd23456d10b9c28d3bc436c4c3/examples/nunjucks/public/.gitkeep -------------------------------------------------------------------------------- /examples/react/README.md: -------------------------------------------------------------------------------- 1 | # Fractal React example 2 | 3 | This is an example instance of Fractal using the React adapter. 4 | 5 | ## Setup 6 | 7 | [Follow these instructions](https://github.com/frctl/fractal#development) to setup the development environement, then run: 8 | 9 | ```bash 10 | npm start 11 | ``` 12 | 13 | to start Fractal server in development mode, or: 14 | 15 | ``` 16 | npm run build 17 | ``` 18 | 19 | to build a static version in the `dist` folder. 20 | 21 | ## Tests 22 | 23 | Run tests from root directory. 24 | -------------------------------------------------------------------------------- /examples/react/components/_preview.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const Preview = (props) => { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 | 15 | ); 16 | }; 17 | 18 | Preview.propTypes = { 19 | foo: PropTypes.string, 20 | yield: PropTypes.string, 21 | _adapter: PropTypes.shape({ 22 | componentName: PropTypes.string, 23 | }), 24 | }; 25 | 26 | export default Preview; 27 | -------------------------------------------------------------------------------- /examples/react/components/collated/__snapshots__/collated.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`collated renders collated components collated 1`] = ` 4 | " 5 |
    Collated component default
    6 | 7 | 8 | 9 |
    Collated component one
    10 | 11 | 12 | 13 |
    Collated component two
    14 | 15 | 16 | 17 |
    Collated component three
    18 | 19 | " 20 | `; 21 | -------------------------------------------------------------------------------- /examples/react/components/collated/collated.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collated: true, 3 | variants: [ 4 | { 5 | context: { 6 | foo: 'bar', 7 | }, 8 | name: 'one', 9 | }, 10 | { 11 | name: 'two', 12 | }, 13 | { 14 | name: 'three', 15 | }, 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /examples/react/components/collated/collated.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const Collated = (props) => { 5 | return
    {`Collated component ${props._self.name}`}
    ; 6 | }; 7 | 8 | Collated.propTypes = { 9 | _self: PropTypes.shape({ 10 | name: PropTypes.string, 11 | }), 12 | }; 13 | 14 | module.exports = Collated; 15 | -------------------------------------------------------------------------------- /examples/react/components/collated/collated.spec.js: -------------------------------------------------------------------------------- 1 | const { collated } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('collated', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | collated(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/react/components/components.spec.js: -------------------------------------------------------------------------------- 1 | const { components } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../fractal.config.js'); 4 | 5 | describe('components', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | components(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/react/components/context/__snapshots__/context.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`tree asynchronously loads context 1`] = ` 4 | Object { 5 | "foo": "bar", 6 | "xkcd": Object { 7 | "alt": "Proper User Policy apparently means Simon Says.", 8 | "day": "28", 9 | "img": "https://imgs.xkcd.com/comics/sandwich.png", 10 | "link": "", 11 | "month": "8", 12 | "news": "", 13 | "num": 149, 14 | "safe_title": "Sandwich", 15 | "title": "Sandwich", 16 | "transcript": "[[ A man is sitting on a couch, talking to another man. They are both stick figures. ]] 17 | First man: Make me a sandwich. 18 | Second man: What? Make it yourself. 19 | First man: Sudo make me a sandwich. 20 | Second man: Okay", 21 | "year": "2006", 22 | }, 23 | } 24 | `; 25 | 26 | exports[`tree loads fully rendered component from another component context key 1`] = `"

    JS Context

    "`; 27 | -------------------------------------------------------------------------------- /examples/react/components/context/async/async.config.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | const response = fetch('https://xkcd.com/149/info.0.json').then((response) => response.json()); 4 | 5 | module.exports = { 6 | context: { 7 | xkcd: response, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /examples/react/components/context/async/async.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const Async = (props) => { 5 | return ( 6 | 7 | {props.xkcd.title} 8 | 9 | ); 10 | }; 11 | 12 | Async.propTypes = { 13 | xkcd: PropTypes.shape({ 14 | num: PropTypes.number, 15 | img: PropTypes.string, 16 | title: PropTypes.string, 17 | }), 18 | }; 19 | 20 | module.exports = Async; 21 | -------------------------------------------------------------------------------- /examples/react/components/context/context.spec.js: -------------------------------------------------------------------------------- 1 | const { context } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('tree', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | context(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/react/components/context/js/js.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | context: { 3 | text: 'JS Context', 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /examples/react/components/context/js/js.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const Js = (props) => { 5 | return

    {props.text}

    ; 6 | }; 7 | 8 | Js.propTypes = { 9 | text: PropTypes.string, 10 | }; 11 | 12 | module.exports = Js; 13 | -------------------------------------------------------------------------------- /examples/react/components/context/json/json.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "context": { 3 | "text": "JSON Context" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/react/components/context/json/json.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const Json = (props) => { 5 | return

    {props.text}

    ; 6 | }; 7 | 8 | Json.propTypes = { 9 | text: PropTypes.string, 10 | }; 11 | 12 | module.exports = Json; 13 | -------------------------------------------------------------------------------- /examples/react/components/context/reference-full/reference-full.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | reference: '@@reference' 3 | -------------------------------------------------------------------------------- /examples/react/components/context/reference-full/reference-full.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const ReferenceFull = (props) => { 5 | return
    {props.reference}
    ; 6 | }; 7 | 8 | ReferenceFull.propTypes = { 9 | reference: PropTypes.string, 10 | }; 11 | 12 | module.exports = ReferenceFull; 13 | -------------------------------------------------------------------------------- /examples/react/components/context/reference-key/reference-key.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: '@js.text' 3 | -------------------------------------------------------------------------------- /examples/react/components/context/reference-key/reference-key.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const ReferenceKey = (props) => { 5 | return

    {props.text}

    ; 6 | }; 7 | 8 | ReferenceKey.propTypes = { 9 | text: PropTypes.string, 10 | }; 11 | 12 | module.exports = ReferenceKey; 13 | -------------------------------------------------------------------------------- /examples/react/components/context/reference/reference.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | parent: '@js' 3 | -------------------------------------------------------------------------------- /examples/react/components/context/reference/reference.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const Reference = (props) => { 5 | return

    {props.parent.text}

    ; 6 | }; 7 | 8 | Reference.propTypes = { 9 | parent: PropTypes.shape({ 10 | text: PropTypes.string, 11 | }), 12 | }; 13 | 14 | module.exports = Reference; 15 | -------------------------------------------------------------------------------- /examples/react/components/context/yaml/yaml.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: YAML Context 3 | -------------------------------------------------------------------------------- /examples/react/components/context/yaml/yaml.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const Yaml = (props) => { 5 | return

    {props.text}

    ; 6 | }; 7 | 8 | Yaml.propTypes = { 9 | text: PropTypes.string, 10 | }; 11 | 12 | module.exports = Yaml; 13 | -------------------------------------------------------------------------------- /examples/react/components/include/__snapshots__/include.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`include does not modify _self when including child component 1`] = `"include-parent--selfinclude childinclude-parent--self"`; 4 | 5 | exports[`include includes child component 1`] = `"include parentinclude child"`; 6 | -------------------------------------------------------------------------------- /examples/react/components/include/include-child/include-child.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const IncludeChild = () => { 4 | return <>include child; 5 | }; 6 | 7 | module.exports = IncludeChild; 8 | -------------------------------------------------------------------------------- /examples/react/components/include/include-parent/include-parent--self.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | // TODO: it should be possible to import components by handles 5 | const IncludeChild = require('../include-child/include-child.jsx'); 6 | 7 | const IncludeParentSelf = (props) => { 8 | return ( 9 | <> 10 | {props._self.handle} 11 | 12 | {props._self.handle} 13 | 14 | ); 15 | }; 16 | 17 | IncludeParentSelf.propTypes = { 18 | _self: PropTypes.shape({ 19 | handle: PropTypes.string, 20 | }), 21 | }; 22 | 23 | module.exports = IncludeParentSelf; 24 | -------------------------------------------------------------------------------- /examples/react/components/include/include-parent/include-parent.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | // TODO: it should be possible to import components by handles 4 | const IncludeChild = require('../include-child/include-child.jsx'); 5 | 6 | const IncludeParent = () => { 7 | return ( 8 | <> 9 | include parent 10 | 11 | 12 | ); 13 | }; 14 | 15 | module.exports = IncludeParent; 16 | -------------------------------------------------------------------------------- /examples/react/components/include/include.spec.js: -------------------------------------------------------------------------------- 1 | const { include } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('include', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | include(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/react/components/notes/notes-config/notes-config.config.yml: -------------------------------------------------------------------------------- 1 | notes: Component Notes 2 | variants: 3 | - name: alt 4 | notes: Component Notes for variant 5 | -------------------------------------------------------------------------------- /examples/react/components/notes/notes-config/notes-config.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const NotesConfig = () => { 4 | return <>Load notes from config; 5 | }; 6 | 7 | module.exports = NotesConfig; 8 | -------------------------------------------------------------------------------- /examples/react/components/notes/notes-files/notes-files--alt.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const NotesFilesAlt = () => { 4 | return <>Load notes from readme files; 5 | }; 6 | 7 | module.exports = NotesFilesAlt; 8 | -------------------------------------------------------------------------------- /examples/react/components/notes/notes-files/notes-files--alt.readme.md: -------------------------------------------------------------------------------- 1 | Component Notes for variant 2 | -------------------------------------------------------------------------------- /examples/react/components/notes/notes-files/notes-files.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const NotesFiles = () => { 4 | return <>Load notes from readme files; 5 | }; 6 | 7 | module.exports = NotesFiles; 8 | -------------------------------------------------------------------------------- /examples/react/components/notes/notes-files/notes-files.readme.md: -------------------------------------------------------------------------------- 1 | Component Notes 2 | -------------------------------------------------------------------------------- /examples/react/components/notes/notes.spec.js: -------------------------------------------------------------------------------- 1 | const { notes } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('notes', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | notes(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/react/components/path/__snapshots__/path.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`path converts absolute path to relative for builder 1`] = `"./some-path.html"`; 4 | 5 | exports[`path renders original path for server 1`] = `"/some-path"`; 6 | -------------------------------------------------------------------------------- /examples/react/components/path/path.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const { usePath } = require('@frctl/react/components'); 4 | 5 | const Path = () => { 6 | const path = usePath(); 7 | return <>{path.get('/some-path')}; 8 | }; 9 | 10 | module.exports = Path; 11 | -------------------------------------------------------------------------------- /examples/react/components/path/path.spec.js: -------------------------------------------------------------------------------- 1 | const { path } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('path', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | path(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/react/components/render/__snapshots__/render.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`render renders component if ssr is turned off but enabled in component meta 1`] = `"Render something"`; 4 | 5 | exports[`render renders component using ES6 import/export syntax 1`] = `"Render something"`; 6 | 7 | exports[`render renders component with renderToStaticMarkup method 1`] = `"Render something"`; 8 | 9 | exports[`render renders default template for default variant 1`] = `"Render something"`; 10 | 11 | exports[`render renders default template for regular variant 1`] = `"Render variant-1"`; 12 | 13 | exports[`render renders specified camelCased template for variant 1`] = `"Render camelCaseVariant something"`; 14 | 15 | exports[`render renders specified template for variant 1`] = `"Render variant-2 something"`; 16 | 17 | exports[`render renders variant template for variant with the same name 1`] = `"Render variant-2 something"`; 18 | 19 | exports[`render renders with preview layout 1`] = `"
    Render something
    "`; 20 | -------------------------------------------------------------------------------- /examples/react/components/render/render--camelCaseVariant.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const RenderCamelCaseVariant = (props) => { 5 | return <>Render camelCaseVariant {props.something}; 6 | }; 7 | 8 | RenderCamelCaseVariant.propTypes = { 9 | something: PropTypes.string, 10 | }; 11 | 12 | module.exports = RenderCamelCaseVariant; 13 | -------------------------------------------------------------------------------- /examples/react/components/render/render--es6-import-export.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const RenderES6ImportExport = (props) => { 5 | return <>Render {props.something}; 6 | }; 7 | 8 | RenderES6ImportExport.propTypes = { 9 | something: PropTypes.string, 10 | }; 11 | 12 | export default RenderES6ImportExport; 13 | -------------------------------------------------------------------------------- /examples/react/components/render/render--variant-2.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const RenderVariant2 = (props) => { 5 | return <>Render variant-2 {props.something}; 6 | }; 7 | 8 | RenderVariant2.propTypes = { 9 | something: PropTypes.string, 10 | }; 11 | 12 | module.exports = RenderVariant2; 13 | -------------------------------------------------------------------------------- /examples/react/components/render/render.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | something: something 3 | variants: 4 | - name: variant-1 5 | context: 6 | something: variant-1 7 | - name: variant-2 8 | - name: variant-3 9 | view: render--variant-2.jsx 10 | - name: variant-4 11 | view: render--camelCaseVariant.jsx 12 | -------------------------------------------------------------------------------- /examples/react/components/render/render.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const Render = (props) => { 5 | return <>Render {props.something}; 6 | }; 7 | 8 | Render.propTypes = { 9 | something: PropTypes.string, 10 | }; 11 | 12 | module.exports = Render; 13 | -------------------------------------------------------------------------------- /examples/react/components/root/root-tree/root-tree-leaf.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const RootTreeLeaf = () => { 4 | return <>root tree leaf; 5 | }; 6 | 7 | module.exports = RootTreeLeaf; 8 | -------------------------------------------------------------------------------- /examples/react/components/root/root.config.yml: -------------------------------------------------------------------------------- 1 | root: true 2 | -------------------------------------------------------------------------------- /examples/react/components/tree/subtree/subtree-leaf/subtree-leaf--variant.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const SubtreeLeafVariant = () => { 4 | return <>Subtree leaf variant; 5 | }; 6 | 7 | module.exports = SubtreeLeafVariant; 8 | -------------------------------------------------------------------------------- /examples/react/components/tree/subtree/subtree-leaf/subtree-leaf.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | subTreeLeaf: true 3 | -------------------------------------------------------------------------------- /examples/react/components/tree/subtree/subtree-leaf/subtree-leaf.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const SubtreeLeaf = () => { 4 | return <>Subtree leaf; 5 | }; 6 | 7 | module.exports = SubtreeLeaf; 8 | -------------------------------------------------------------------------------- /examples/react/components/tree/subtree/subtree.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | level: 2 3 | subTree: true 4 | -------------------------------------------------------------------------------- /examples/react/components/tree/tree-leaf/tree-leaf--variant.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const TreeLeafVariant = () => { 4 | return <>Tree leaf variant; 5 | }; 6 | 7 | module.exports = TreeLeafVariant; 8 | -------------------------------------------------------------------------------- /examples/react/components/tree/tree-leaf/tree-leaf.config.yml: -------------------------------------------------------------------------------- 1 | variants: 2 | - name: another 3 | context: 4 | level: 2 5 | -------------------------------------------------------------------------------- /examples/react/components/tree/tree-leaf/tree-leaf.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const TreeLeaf = (props) => { 5 | return <>Tree leaf {props._self.name}; 6 | }; 7 | 8 | TreeLeaf.propTypes = { 9 | _self: PropTypes.shape({ 10 | name: PropTypes.string, 11 | }), 12 | }; 13 | 14 | module.exports = TreeLeaf; 15 | -------------------------------------------------------------------------------- /examples/react/components/tree/tree.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | level: 1 3 | root: true 4 | -------------------------------------------------------------------------------- /examples/react/components/tree/tree.spec.js: -------------------------------------------------------------------------------- 1 | const { tree } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('tree', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | tree(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/react/components/wrapper/__snapshots__/wrapper.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`wrapper renders with wrapper elements 1`] = `"wrapped consumer"`; 4 | -------------------------------------------------------------------------------- /examples/react/components/wrapper/wrapper-consumer/wrapper-consumer.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | const { WrapperContext } = require('../wrapper-provider/wrapper-provider.jsx'); 4 | 5 | const WrapperConsumer = () => { 6 | const { getValue } = React.useContext(WrapperContext); 7 | 8 | return <>{getValue('consumer')}; 9 | }; 10 | 11 | module.exports = WrapperConsumer; 12 | -------------------------------------------------------------------------------- /examples/react/components/wrapper/wrapper-provider/wrapper-provider.jsx: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const WrapperContext = React.createContext({ 5 | getValue: (value) => value, 6 | }); 7 | 8 | const WrapperProvider = (props) => { 9 | const { children, ...rest } = props; 10 | return {children}; 11 | }; 12 | 13 | WrapperProvider.propTypes = { 14 | children: PropTypes.node, 15 | getValue: PropTypes.func, 16 | }; 17 | 18 | module.exports = WrapperProvider; 19 | module.exports.WrapperContext = WrapperContext; 20 | -------------------------------------------------------------------------------- /examples/react/components/wrapper/wrapper.spec.js: -------------------------------------------------------------------------------- 1 | const fractal = require('../../fractal.config.js'); 2 | 3 | describe('wrapper', () => { 4 | beforeEach(async () => { 5 | await fractal.load(); 6 | }); 7 | 8 | it('renders with wrapper elements', async () => { 9 | const render = await fractal.components.find('@wrapper-consumer').render(); 10 | expect(render).toMatchSnapshot(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /examples/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/react-example", 3 | "version": "0.2.11", 4 | "private": true, 5 | "scripts": { 6 | "start": "fractal start --sync", 7 | "build": "fractal build" 8 | }, 9 | "dependencies": { 10 | "@frctl/fractal": "^1.5.15", 11 | "@frctl/mandelbrot": "^1.10.3", 12 | "@frctl/react": "^0.3.7" 13 | }, 14 | "devDependencies": { 15 | "@frctl/adapter-tests": "^0.2.0", 16 | "node-fetch": "^2.6.1", 17 | "prop-types": "^15.7.2", 18 | "react": "^17.0.2", 19 | "react-dom": "^17.0.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/twig/README.md: -------------------------------------------------------------------------------- 1 | # Fractal Twig example 2 | 3 | This is an example instance of Fractal using the Twig adapter. 4 | 5 | ## Setup 6 | 7 | [Follow these instructions](https://github.com/frctl/fractal#development) to setup the development environement, then run: 8 | 9 | ```bash 10 | npm start 11 | ``` 12 | 13 | to start Fractal server in development mode, or: 14 | 15 | ``` 16 | npm run build 17 | ``` 18 | 19 | to build a static version in the `dist` folder. 20 | 21 | ## Tests 22 | 23 | Run tests from root directory. 24 | -------------------------------------------------------------------------------- /examples/twig/components/collated/__snapshots__/collated.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`collated renders collated components collated 1`] = ` 4 | " 5 |
    6 | Collated component default 7 |
    8 | 9 | 10 | 11 |
    12 | Collated component one 13 |
    14 | 15 | 16 | 17 |
    18 | Collated component two 19 |
    20 | 21 | 22 | 23 |
    24 | Collated component three 25 |
    26 | 27 | " 28 | `; 29 | -------------------------------------------------------------------------------- /examples/twig/components/collated/collated.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collated: true, 3 | variants: [ 4 | { 5 | context: { 6 | foo: 'bar', 7 | }, 8 | name: 'one', 9 | }, 10 | { 11 | name: 'two', 12 | }, 13 | { 14 | name: 'three', 15 | }, 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /examples/twig/components/collated/collated.spec.js: -------------------------------------------------------------------------------- 1 | const { collated } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('collated', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | collated(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/components/collated/collated.twig: -------------------------------------------------------------------------------- 1 |
    2 | Collated component {{ _self.name }} 3 |
    4 | -------------------------------------------------------------------------------- /examples/twig/components/components.spec.js: -------------------------------------------------------------------------------- 1 | const { components } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../fractal.config.js'); 4 | 5 | describe('components', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | components(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/components/context/__snapshots__/context.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`tree asynchronously loads context 1`] = ` 4 | Object { 5 | "xkcd": Object { 6 | "alt": "Proper User Policy apparently means Simon Says.", 7 | "day": "28", 8 | "img": "https://imgs.xkcd.com/comics/sandwich.png", 9 | "link": "", 10 | "month": "8", 11 | "news": "", 12 | "num": 149, 13 | "safe_title": "Sandwich", 14 | "title": "Sandwich", 15 | "transcript": "[[ A man is sitting on a couch, talking to another man. They are both stick figures. ]] 16 | First man: Make me a sandwich. 17 | Second man: What? Make it yourself. 18 | First man: Sudo make me a sandwich. 19 | Second man: Okay", 20 | "year": "2006", 21 | }, 22 | } 23 | `; 24 | 25 | exports[`tree loads fully rendered component from another component context key 1`] = ` 26 | "

    JS Context

    27 | " 28 | `; 29 | -------------------------------------------------------------------------------- /examples/twig/components/context/async/async.config.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | const response = fetch('https://xkcd.com/149/info.0.json').then((response) => response.json()); 4 | 5 | module.exports = { 6 | context: { 7 | xkcd: response, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /examples/twig/components/context/async/async.twig: -------------------------------------------------------------------------------- 1 | 2 | {{ xkcd.title }} 3 | 4 | -------------------------------------------------------------------------------- /examples/twig/components/context/context.spec.js: -------------------------------------------------------------------------------- 1 | const { context } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('tree', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | context(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/components/context/js/js.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | context: { 3 | text: 'JS Context', 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /examples/twig/components/context/js/js.twig: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/twig/components/context/json/json.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "context": { 3 | "text": "JSON Context" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/twig/components/context/json/json.twig: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/twig/components/context/reference-full/reference-full.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | reference: '@@reference' 3 | -------------------------------------------------------------------------------- /examples/twig/components/context/reference-full/reference-full.twig: -------------------------------------------------------------------------------- 1 |
    {{ reference }}
    2 | -------------------------------------------------------------------------------- /examples/twig/components/context/reference-key/reference-key.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: '@js.text' 3 | -------------------------------------------------------------------------------- /examples/twig/components/context/reference-key/reference-key.twig: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/twig/components/context/reference/reference.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | parent: '@js' 3 | -------------------------------------------------------------------------------- /examples/twig/components/context/reference/reference.twig: -------------------------------------------------------------------------------- 1 |

    {{ parent.text }}

    2 | -------------------------------------------------------------------------------- /examples/twig/components/context/yaml/yaml.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: YAML Context 3 | -------------------------------------------------------------------------------- /examples/twig/components/context/yaml/yaml.twig: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /examples/twig/components/include/__snapshots__/include.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`include does not modify _self when including child component 1`] = ` 4 | "include-parent--self 5 | include child 6 | include-parent--self 7 | " 8 | `; 9 | 10 | exports[`include includes child component 1`] = ` 11 | "include parent 12 | include child 13 | " 14 | `; 15 | -------------------------------------------------------------------------------- /examples/twig/components/include/include-child/include-child.twig: -------------------------------------------------------------------------------- 1 | include child 2 | -------------------------------------------------------------------------------- /examples/twig/components/include/include-parent/include-parent--self.twig: -------------------------------------------------------------------------------- 1 | {{ _self.handle }} 2 | {% include '@include-child' %} 3 | {{ _self.handle }} 4 | -------------------------------------------------------------------------------- /examples/twig/components/include/include-parent/include-parent.twig: -------------------------------------------------------------------------------- 1 | include parent 2 | {% include '@include-child' %} 3 | -------------------------------------------------------------------------------- /examples/twig/components/include/include.spec.js: -------------------------------------------------------------------------------- 1 | const { include } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('include', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | include(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/components/notes/notes-config/notes-config.config.yml: -------------------------------------------------------------------------------- 1 | notes: Component Notes 2 | variants: 3 | - name: alt 4 | notes: Component Notes for variant 5 | -------------------------------------------------------------------------------- /examples/twig/components/notes/notes-config/notes-config.twig: -------------------------------------------------------------------------------- 1 | Load notes from config 2 | -------------------------------------------------------------------------------- /examples/twig/components/notes/notes-files/notes-files--alt.readme.md: -------------------------------------------------------------------------------- 1 | Component Notes for variant 2 | -------------------------------------------------------------------------------- /examples/twig/components/notes/notes-files/notes-files--alt.twig: -------------------------------------------------------------------------------- 1 | Load notes from readme files 2 | -------------------------------------------------------------------------------- /examples/twig/components/notes/notes-files/notes-files.readme.md: -------------------------------------------------------------------------------- 1 | Component Notes 2 | -------------------------------------------------------------------------------- /examples/twig/components/notes/notes-files/notes-files.twig: -------------------------------------------------------------------------------- 1 | Load notes from readme files 2 | -------------------------------------------------------------------------------- /examples/twig/components/notes/notes.spec.js: -------------------------------------------------------------------------------- 1 | const { notes } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('notes', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | notes(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/components/path/__snapshots__/path.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`path converts absolute path to relative for builder 1`] = ` 4 | "./some-path.html 5 | " 6 | `; 7 | 8 | exports[`path renders original path for server 1`] = ` 9 | "/some-path 10 | " 11 | `; 12 | -------------------------------------------------------------------------------- /examples/twig/components/path/path.spec.js: -------------------------------------------------------------------------------- 1 | const { path } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('path', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | path(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/components/path/path.twig: -------------------------------------------------------------------------------- 1 | {{ '/some-path' | path }} 2 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-1.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | text: Default Context 3 | container: 4 | text: Default Context 5 | variants: 6 | - name: variant 7 | context: 8 | text: Variant Context 9 | container: 10 | text: Variant Context 11 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-1.twig: -------------------------------------------------------------------------------- 1 | {{ container.text }} 2 | {{ text }} 3 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-2--escaped-handle.twig: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-escaped-handle' %} 2 | 3 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-2--missing-handle.twig: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-comp-3' %} 2 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-2--no-context.twig: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-comp-1' %} 2 | 3 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-2--variant.twig: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-comp-1--variant' with newContext %} 2 | 3 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-2--wrong-handle.twig: -------------------------------------------------------------------------------- 1 | {% render 'render-tag-comp-1' %} 2 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-2.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | newContext: 3 | container: 4 | text: Override Context 5 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/comp-2.twig: -------------------------------------------------------------------------------- 1 | {% render '@render-tag-comp-1' with newContext %} 2 | 3 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/config.yml: -------------------------------------------------------------------------------- 1 | prefix: render-tag 2 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/escaped-handle.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | handle: '\@render-tag-comp-1' 3 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/escaped-handle.twig: -------------------------------------------------------------------------------- 1 | {{ handle }} 2 | -------------------------------------------------------------------------------- /examples/twig/components/render-tag/render-tag.spec.js: -------------------------------------------------------------------------------- 1 | const { renderTag } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('render-tag', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | renderTag(fractal); 11 | 12 | it('throws if specified handle is wrong', async () => { 13 | expect(async () => { 14 | return await fractal.components.find('@render-tag-comp-2--wrong-handle').render(); 15 | }).rejects.toThrow('You must provide a valid component handle to the render tag.'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /examples/twig/components/render/__snapshots__/render.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`render renders default template for default variant 1`] = ` 4 | "Render something 5 | " 6 | `; 7 | 8 | exports[`render renders default template for regular variant 1`] = ` 9 | "Render variant-1 10 | " 11 | `; 12 | 13 | exports[`render renders specified camelCased template for variant 1`] = ` 14 | "Render camelCaseVariant something 15 | " 16 | `; 17 | 18 | exports[`render renders specified template for variant 1`] = ` 19 | "Render variant-2 something 20 | " 21 | `; 22 | 23 | exports[`render renders variant template for variant with the same name 1`] = ` 24 | "Render variant-2 something 25 | " 26 | `; 27 | -------------------------------------------------------------------------------- /examples/twig/components/render/render--camelCaseVariant.twig: -------------------------------------------------------------------------------- 1 | Render camelCaseVariant {{ something }} 2 | -------------------------------------------------------------------------------- /examples/twig/components/render/render--variant-2.twig: -------------------------------------------------------------------------------- 1 | Render variant-2 {{ something }} 2 | -------------------------------------------------------------------------------- /examples/twig/components/render/render.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | something: something 3 | variants: 4 | - name: variant-1 5 | context: 6 | something: variant-1 7 | - name: variant-2 8 | - name: variant-3 9 | view: render--variant-2.twig 10 | - name: variant-4 11 | view: render--camelCaseVariant.twig 12 | -------------------------------------------------------------------------------- /examples/twig/components/render/render.spec.js: -------------------------------------------------------------------------------- 1 | const { render } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('render', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | render(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/components/render/render.twig: -------------------------------------------------------------------------------- 1 | Render {{ something }} 2 | -------------------------------------------------------------------------------- /examples/twig/components/root/root-tree/root-tree-leaf.twig: -------------------------------------------------------------------------------- 1 | root tree leaf 2 | -------------------------------------------------------------------------------- /examples/twig/components/root/root.config.yml: -------------------------------------------------------------------------------- 1 | root: true 2 | -------------------------------------------------------------------------------- /examples/twig/components/tree/subtree/subtree-leaf/subtree-leaf--variant.twig: -------------------------------------------------------------------------------- 1 | Subtree leaf variant 2 | -------------------------------------------------------------------------------- /examples/twig/components/tree/subtree/subtree-leaf/subtree-leaf.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | subTreeLeaf: true 3 | -------------------------------------------------------------------------------- /examples/twig/components/tree/subtree/subtree-leaf/subtree-leaf.twig: -------------------------------------------------------------------------------- 1 | Subtree leaf 2 | -------------------------------------------------------------------------------- /examples/twig/components/tree/subtree/subtree.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | level: 2 3 | subTree: true 4 | -------------------------------------------------------------------------------- /examples/twig/components/tree/tree-leaf/tree-leaf--variant.twig: -------------------------------------------------------------------------------- 1 | Tree leaf variant 2 | -------------------------------------------------------------------------------- /examples/twig/components/tree/tree-leaf/tree-leaf.config.yml: -------------------------------------------------------------------------------- 1 | variants: 2 | - name: another 3 | context: 4 | level: 2 5 | -------------------------------------------------------------------------------- /examples/twig/components/tree/tree-leaf/tree-leaf.twig: -------------------------------------------------------------------------------- 1 | Tree leaf {{ _self.name }} 2 | -------------------------------------------------------------------------------- /examples/twig/components/tree/tree.config.yml: -------------------------------------------------------------------------------- 1 | context: 2 | level: 1 3 | root: true 4 | -------------------------------------------------------------------------------- /examples/twig/components/tree/tree.spec.js: -------------------------------------------------------------------------------- 1 | const { tree } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../../fractal.config.js'); 4 | 5 | describe('tree', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | tree(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/docs/01-index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Project Overview 3 | context: 4 | items: 5 | - Finish the docs 6 | - Write tests 7 | - Make the tea 8 | --- 9 | 10 | This is some documentation for the project. Still to do: 11 | 12 | {% for item in items %} 13 | 14 | - {{ item }} 15 | {% endfor %} 16 | -------------------------------------------------------------------------------- /examples/twig/docs/__snapshots__/docs.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`docs properly render docs through templating engine 1`] = ` 4 | "

    This is some documentation for the project. Still to do:

    5 |
      6 |
    • Finish the docs

      7 |
    • 8 |
    • Write tests

      9 |
    • 10 |
    • Make the tea

      11 |
    • 12 |
    13 | " 14 | `; 15 | -------------------------------------------------------------------------------- /examples/twig/docs/docs.spec.js: -------------------------------------------------------------------------------- 1 | const { docs } = require('@frctl/adapter-tests'); 2 | 3 | const fractal = require('../fractal.config.js'); 4 | 5 | describe('docs', () => { 6 | beforeEach(async () => { 7 | await fractal.load(); 8 | }); 9 | 10 | docs(fractal); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/twig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/twig-example", 3 | "version": "0.2.11", 4 | "private": true, 5 | "scripts": { 6 | "start": "fractal start --sync", 7 | "build": "fractal build" 8 | }, 9 | "dependencies": { 10 | "@frctl/fractal": "^1.5.15", 11 | "@frctl/mandelbrot": "^1.10.3", 12 | "@frctl/twig": "^1.2.13" 13 | }, 14 | "devDependencies": { 15 | "@frctl/adapter-tests": "^0.2.0", 16 | "node-fetch": "^2.6.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | testEnvironment: 'node', 6 | setupFilesAfterEnv: ['./tests/setup.js'], 7 | }; 8 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": { 3 | "version": { 4 | "allowBranch": "main", 5 | "message": "chore: publish" 6 | } 7 | }, 8 | "packages": ["packages/*", "examples/*"], 9 | "version": "independent" 10 | } 11 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # @frctl/core 2 | 3 | The core module of [Fractal](http://github.com/frctl/fractal). 4 | 5 | [![NPM Version](https://img.shields.io/npm/v/@frctl/core)](https://www.npmjs.com/package/@frctl/core) 6 | 7 | ## License 8 | 9 | [MIT](https://github.com/frctl/fractal/blob/main/LICENSE) 10 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/core", 3 | "version": "0.3.5", 4 | "description": "Core module of Fractal.", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/frctl/fractal.git", 9 | "directory": "packages/core" 10 | }, 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/frctl/fractal/issues" 14 | }, 15 | "homepage": "https://github.com/frctl/fractal/tree/main/packages/core", 16 | "dependencies": { 17 | "@allmarkedup/fang": "^2.0.0", 18 | "anymatch": "^3.1.2", 19 | "bluebird": "^3.7.2", 20 | "chokidar": "^3.5.1", 21 | "co": "^4.6.0", 22 | "fs-extra": "^9.1.0", 23 | "globby": "^11.0.3", 24 | "highlight.js": "^10.7.2", 25 | "istextorbinary": "^5.15.0", 26 | "js-yaml": "^4.1.0", 27 | "lodash": "^4.17.21", 28 | "marked": "^2.0.3", 29 | "minimist": "^1.2.5", 30 | "mixwith": "^0.1.1", 31 | "readable-stream": "^3.6.0" 32 | }, 33 | "devDependencies": { 34 | "mock-argv": "^1.1.15", 35 | "mock-fs": "^4.14.0" 36 | }, 37 | "publishConfig": { 38 | "access": "public" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/core/src/array-stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Readable = require('readable-stream').Readable; 4 | 5 | module.exports = class ArrayStream extends Readable { 6 | constructor(items) { 7 | super({ objectMode: true }); 8 | this._items = items; 9 | this._pointer = 0; 10 | } 11 | 12 | _read() { 13 | this.push(this._pointer < this._items.length ? this._items[this._pointer++] : null); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /packages/core/src/entities/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Collection: require('./collection'), 3 | Entity: require('./entity'), 4 | Source: require('./source'), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/core/src/highlighter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const HighlightJs = require('highlight.js'); 4 | const _ = require('lodash'); 5 | 6 | module.exports = function highlighter(content, lang) { 7 | content = _.toString(content || ''); 8 | lang = lang ? lang.toLowerCase() : lang; 9 | try { 10 | return lang 11 | ? HighlightJs.highlight(content, { language: lang }).value 12 | : HighlightJs.highlightAuto(content).value; 13 | } catch (e) { 14 | return HighlightJs.highlightAuto(content).value; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /packages/core/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Adapter: require('./adapter'), 3 | ArrayStream: require('./array-stream'), 4 | data: require('./data'), 5 | entities: require('./entities'), 6 | fs: require('./fs'), 7 | highlighter: require('./highlighter'), 8 | Log: require('./log'), 9 | markdown: require('./markdown'), 10 | mixins: require('./mixins'), 11 | PromiseStream: require('./promise-stream'), 12 | resolver: require('./resolver'), 13 | shell: require('./shell'), 14 | utils: require('./utils'), 15 | }; 16 | -------------------------------------------------------------------------------- /packages/core/src/log.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mix = require('./mixins/mix'); 4 | const Emitter = require('./mixins/emitter'); 5 | 6 | class Log extends mix(Emitter) { 7 | log(msg, data) { 8 | this.emit('log', msg, data); 9 | } 10 | 11 | write(msg, data) { 12 | this.emit('log', msg, data); 13 | } 14 | 15 | debug(msg, data) { 16 | this.emit('debug', msg, data); 17 | } 18 | 19 | success(msg, data) { 20 | this.emit('success', msg, data); 21 | } 22 | 23 | error(msg, data) { 24 | this.emit('error', msg, data); 25 | } 26 | 27 | warn(msg, data) { 28 | this.emit('warn', msg, data); 29 | } 30 | } 31 | 32 | module.exports = new Log(); 33 | -------------------------------------------------------------------------------- /packages/core/src/mixins/configurable.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const mixin = require('mixwith').Mixin; 5 | 6 | module.exports = mixin( 7 | (superclass) => 8 | class Configurable extends superclass { 9 | constructor() { 10 | super(); 11 | super.addMixedIn('Configurable'); 12 | this._config = {}; 13 | } 14 | 15 | config(config) { 16 | if (_.isUndefined(config)) { 17 | return this._config; 18 | } 19 | this._config = config || {}; 20 | return this; 21 | } 22 | 23 | set(config, val) { 24 | _.set(this._config, config, val); 25 | return this; 26 | } 27 | 28 | get(config, defaultVal) { 29 | if (_.isUndefined(config)) { 30 | return this._config; 31 | } 32 | return _.get(this._config, config, defaultVal || undefined); 33 | } 34 | } 35 | ); 36 | -------------------------------------------------------------------------------- /packages/core/src/mixins/emitter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const { Mixin } = require('mixwith'); 5 | const { EventEmitter } = require('events'); 6 | 7 | module.exports = Mixin((superclass) => { 8 | const Emitter = class extends superclass { 9 | constructor() { 10 | super(); 11 | super.addMixedIn('Emitter'); 12 | } 13 | }; 14 | 15 | _.extend(Emitter.prototype, EventEmitter.prototype); 16 | 17 | return Emitter; 18 | }); 19 | -------------------------------------------------------------------------------- /packages/core/src/mixins/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collection: require('./collection'), 3 | configurable: require('./configurable'), 4 | emitter: require('./emitter'), 5 | entity: require('./entity'), 6 | heritable: require('./heritable'), 7 | mix: require('./mix'), 8 | source: require('./source'), 9 | }; 10 | -------------------------------------------------------------------------------- /packages/core/src/mixins/mix.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const mix = require('mixwith').mix; 5 | 6 | class Base { 7 | constructor() { 8 | Object.defineProperty(this, '_mixedIn', { 9 | enumerable: false, 10 | configurable: false, 11 | writable: true, 12 | value: [], 13 | }); 14 | } 15 | 16 | hasMixedIn(name) { 17 | return _.includes(this._mixedIn, name); 18 | } 19 | 20 | addMixedIn(name) { 21 | this._mixedIn.push(name); 22 | this._mixedIn = _.uniq(this._mixedIn); 23 | } 24 | } 25 | 26 | module.exports = function () { 27 | const mixer = mix(Base); 28 | return mixer.with.apply(mixer, Array.from(arguments)); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/core/src/promise-stream.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Promise = require('bluebird'); 4 | const Readable = require('readable-stream').Readable; 5 | 6 | module.exports = class PromiseStream extends Readable { 7 | constructor(p) { 8 | super({ objectMode: true }); 9 | this._data = Promise.resolve(p); 10 | this._fulfilledOnInit = this._data.isFulfilled(); 11 | if (!this._fulfilledOnInit) { 12 | this._data.then((items) => { 13 | items.forEach((i) => this.push(i)); 14 | }); 15 | } 16 | this._data.catch((err) => { 17 | this.emit('error', err); 18 | }); 19 | } 20 | 21 | _read() { 22 | if (this._fulfilledOnInit) { 23 | this._data.value().forEach((i) => this.push(i)); 24 | this.push(null); 25 | return; 26 | } 27 | if (this._data.isFulfilled()) { 28 | this._data.finally(() => { 29 | this.push(null); 30 | }); 31 | } 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /packages/core/src/shell.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | module.exports = { 4 | /** 5 | * Change the current working directory. 6 | * 7 | * @param {string} [directory=''] The directory to navigate into. 8 | */ 9 | cd(directory = '') { 10 | return process.chdir(directory); 11 | }, 12 | 13 | /** 14 | * Create a file. 15 | * 16 | * @param {string} filename The filename of the file to create. 17 | */ 18 | touch(filename) { 19 | fs.closeSync(fs.openSync(filename, 'w')); 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /packages/core/test/__mocks__/fractal.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | get: jest.fn((key) => { 3 | if (key === 'foo') { 4 | return { 5 | statuses: { 6 | wip: 'wip', 7 | ready: 'ready', 8 | }, 9 | default: { 10 | status: 'wip', 11 | }, 12 | path: './fooPath', 13 | engine: { 14 | register: () => { 15 | return { 16 | foo: 'bar', 17 | load: jest.fn(), 18 | }; 19 | }, 20 | }, 21 | }; 22 | } 23 | }), 24 | }; 25 | -------------------------------------------------------------------------------- /packages/core/test/__snapshots__/markdown.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Markdown renderer renders code correctly 1`] = ` 4 | "
    module.exports = {
     5 |     foo: 'bar',
     6 | };
    " 7 | `; 8 | 9 | exports[`Markdown renderer renders code with lang correctly 1`] = ` 10 | "
    module.exports = {
    11 |     foo: 'bar',
    12 | };
    " 13 | `; 14 | 15 | exports[`Markdown renderer renders markdown correctly 1`] = ` 16 | "

    foo

    17 | " 18 | `; 19 | -------------------------------------------------------------------------------- /packages/core/test/entities/__snapshots__/source.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`EntitySource .toJSON() returns a plain object 1`] = ` 4 | Object { 5 | "fullPath": "", 6 | "isCollection": true, 7 | "isLoaded": false, 8 | "isSource": true, 9 | "isWatching": false, 10 | "items": Array [ 11 | Object { 12 | "id": 1, 13 | "type": "component", 14 | }, 15 | Object { 16 | "id": 2, 17 | "type": "component", 18 | }, 19 | ], 20 | "label": "Foo", 21 | "name": "foo", 22 | "path": "./fooPath", 23 | "relPath": "fooPath", 24 | "title": "Foo", 25 | "viewExt": undefined, 26 | } 27 | `; 28 | -------------------------------------------------------------------------------- /packages/core/test/markdown.spec.js: -------------------------------------------------------------------------------- 1 | const md = require('../src/markdown'); 2 | 3 | const code = ` 4 | \`\`\` 5 | module.exports = { 6 | foo: 'bar', 7 | }; 8 | \`\`\` 9 | `; 10 | 11 | const codeWithLang = ` 12 | \`\`\`js 13 | module.exports = { 14 | foo: 'bar', 15 | }; 16 | \`\`\` 17 | `; 18 | 19 | describe('Markdown renderer', () => { 20 | it('does not directly mutate the supplied configuration object', () => { 21 | const config = {}; 22 | md('**foo**', config); 23 | expect(config).toEqual({}); 24 | }); 25 | 26 | it('renders markdown correctly', () => { 27 | const result = md('**foo**'); 28 | expect(result).toMatchSnapshot(); 29 | }); 30 | 31 | it('renders code correctly', () => { 32 | const result = md(code); 33 | expect(result).toMatchSnapshot(); 34 | }); 35 | 36 | it('renders code with lang correctly', () => { 37 | const result = md(codeWithLang); 38 | expect(result).toMatchSnapshot(); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /packages/core/test/mixins/emitter.spec.js: -------------------------------------------------------------------------------- 1 | const mix = require('../../src/mixins/mix'); 2 | const Emitter = mix(require('../../src/mixins/emitter')); 3 | 4 | describe('Emitter', () => { 5 | let emitter; 6 | 7 | beforeEach(() => { 8 | emitter = new Emitter(); 9 | }); 10 | 11 | it('is an event emitter', () => { 12 | expect(typeof emitter.on).toBe('function'); 13 | expect(typeof emitter.emit).toBe('function'); 14 | }); 15 | 16 | it('is mixed in', () => { 17 | expect(emitter.hasMixedIn('Emitter')).toBe(true); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/fractal/src/api/assets/asset.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Path = require('path'); 4 | const File = require('../files/file'); 5 | 6 | module.exports = class Asset extends File { 7 | constructor(file, relativeTo, source) { 8 | super(file, relativeTo); 9 | this.isAsset = true; 10 | this._source = source; 11 | this.srcPath = Path.join(`${source.name}`, this.relPath); 12 | } 13 | 14 | toVinyl() { 15 | const file = super.toVinyl(); 16 | file.srcPath = this.srcPath; 17 | return file; 18 | } 19 | 20 | toJSON() { 21 | const self = super.toJSON(); 22 | self.isAsset = true; 23 | self.srcPath = this.srcPath; 24 | self[`is${this.ext.replace(/^\./, '').toUpperCase()}`] = true; 25 | return self; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /packages/fractal/src/api/assets/collection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const FileCollection = require('../files/collection'); 4 | 5 | module.exports = class AssetCollection extends FileCollection { 6 | constructor(config, items) { 7 | super(config, items); 8 | } 9 | 10 | assets() { 11 | return this.newSelf(this.toArray().filter((i) => i.isAsset)); 12 | } 13 | 14 | toVinylArray() { 15 | return this.filter('isAsset') 16 | .flatten() 17 | .map((asset) => asset.toVinyl()) 18 | .toArray(); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /packages/fractal/src/api/assets/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./source-collection'); 2 | -------------------------------------------------------------------------------- /packages/fractal/src/api/components/collection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EntityCollection = require('@frctl/core').entities.Collection; 4 | 5 | module.exports = class ComponentCollection extends EntityCollection { 6 | constructor(config, items, parent) { 7 | super(config.name, config, items, parent); 8 | } 9 | 10 | find() { 11 | return this.source.find.apply(this, arguments); 12 | } 13 | 14 | components() { 15 | return super.entities(); 16 | } 17 | 18 | variants() { 19 | return this.source.variants.apply(this, arguments); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /packages/fractal/src/api/components/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./source'); 2 | -------------------------------------------------------------------------------- /packages/fractal/src/api/docs/collection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EntityCollection = require('@frctl/core').entities.Collection; 4 | 5 | module.exports = class DocCollection extends EntityCollection { 6 | constructor(config, items, parent) { 7 | super(config.name, config, items, parent); 8 | } 9 | 10 | pages() { 11 | return super.entities(); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /packages/fractal/src/api/docs/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./source'); 2 | -------------------------------------------------------------------------------- /packages/fractal/src/cli/commands/info.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | command: 'info', 5 | 6 | config: { 7 | description: 'Get information about your Fractal installation', 8 | options: [], 9 | scope: ['global', 'project'], 10 | }, 11 | 12 | action() { 13 | const cli = this.fractal.cli; 14 | const header = 'Fractal install info'; 15 | const footer = null; 16 | let body = ''; 17 | 18 | if (cli.scope === 'project') { 19 | body += `Project Fractal version: ${this.fractal.version}\n`; 20 | } 21 | body += `CLI helper version: ${this.fractal.cli.cliPackage.version}`; 22 | 23 | return this.console.box(header, body, footer).unslog(); 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/fractal/src/cli/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./cli'); 2 | -------------------------------------------------------------------------------- /packages/fractal/src/cli/notifier.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const chalk = require('chalk'); 4 | 5 | class Notifier { 6 | constructor(console, interactive) { 7 | this._console = console; 8 | this._interactive = interactive; 9 | } 10 | 11 | updateAvailable(details) { 12 | this._console.br(); 13 | this._console 14 | .box( 15 | null, 16 | `Fractal update available! ${chalk.dim(details.current)} → ${chalk.green(details.latest)} 17 | Run ${chalk.cyan('npm i -g ' + details.name)} to update.` 18 | ) 19 | .unslog(); 20 | this._console.br(); 21 | } 22 | 23 | versionMismatch(details) { 24 | this._console.log(`Fractal version mismatch! Global: ${details.cli} / Local: ${details.local}`); 25 | } 26 | } 27 | 28 | module.exports = Notifier; 29 | -------------------------------------------------------------------------------- /packages/fractal/src/cli/themes/default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Theme = require('../theme'); 4 | 5 | module.exports = new Theme(); 6 | -------------------------------------------------------------------------------- /packages/fractal/views/cli/new/components/example/example.config.yml: -------------------------------------------------------------------------------- 1 | title: Example component 2 | context: 3 | text: This is an example component! 4 | -------------------------------------------------------------------------------- /packages/fractal/views/cli/new/components/example/example.hbs: -------------------------------------------------------------------------------- 1 |

    {{ text }}

    2 | -------------------------------------------------------------------------------- /packages/fractal/views/cli/new/docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: {{ projectTitle }} 3 | --- 4 | 5 | This is your index page. You can edit its contents at `{{ docsDir }}/01-index.md` 6 | -------------------------------------------------------------------------------- /packages/fractal/views/cli/new/fractal.hbs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | * Require the path module 5 | */ 6 | const path = require('path'); 7 | 8 | /* 9 | * Require the Fractal module 10 | */ 11 | const fractal = module.exports = require('@frctl/fractal').create(); 12 | 13 | {{#if projectTitle}} 14 | /* 15 | * Give your project a title. 16 | */ 17 | fractal.set('project.title', '{{ projectTitle }}'); 18 | {{/if}} 19 | 20 | {{#if componentsDir}} 21 | /* 22 | * Tell Fractal where to look for components. 23 | */ 24 | fractal.components.set('path', path.join(__dirname, '{{ componentsDir }}')); 25 | {{/if}} 26 | 27 | {{#if docsDir}} 28 | /* 29 | * Tell Fractal where to look for documentation pages. 30 | */ 31 | fractal.docs.set('path', path.join(__dirname, '{{ docsDir }}')); 32 | {{/if}} 33 | 34 | {{#if publicDir}} 35 | /* 36 | * Tell the Fractal web preview plugin where to look for static assets. 37 | */ 38 | fractal.web.set('static.path', path.join(__dirname, '{{ publicDir }}')); 39 | {{/if}} 40 | -------------------------------------------------------------------------------- /packages/handlebars/README.md: -------------------------------------------------------------------------------- 1 | # @frctl/handlebars 2 | 3 | [Handlebars](https://handlebarsjs.com/) template engine adapter for [Fractal](http://github.com/frctl/fractal). 4 | 5 | [![NPM Version](https://img.shields.io/npm/v/@frctl/handlebars)](https://www.npmjs.com/package/@frctl/handlebars) 6 | 7 | See the Fractal [view templates guide](http://fractal.build/guide/core-concepts/views) for details on customisation and usage. 8 | 9 | ## License 10 | 11 | [MIT](https://github.com/frctl/fractal/blob/main/LICENSE) 12 | -------------------------------------------------------------------------------- /packages/handlebars/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./src/adapter'); 4 | -------------------------------------------------------------------------------- /packages/handlebars/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/handlebars", 3 | "version": "1.2.15", 4 | "description": "Use Handlebars templates with Fractal.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/frctl/fractal.git", 9 | "directory": "packages/handlebars" 10 | }, 11 | "author": "Mark Perkins (http://clearleft.com/)", 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/frctl/fractal/issues" 15 | }, 16 | "homepage": "https://github.com/frctl/fractal/tree/main/packages/handlebars", 17 | "dependencies": { 18 | "@frctl/core": "^0.3.5", 19 | "bluebird": "^3.7.2", 20 | "handlebars": "^4.7.7", 21 | "lodash": "^4.17.21", 22 | "promised-handlebars": "^2.0.1" 23 | }, 24 | "peerDependencies": { 25 | "@frctl/fractal": "^1.1.0" 26 | }, 27 | "publishConfig": { 28 | "access": "public" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/handlebars/src/helpers/context-data.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const utils = require('@frctl/core').utils; 5 | 6 | module.exports = function (fractal) { 7 | return function render(handle) { 8 | let context; 9 | let source = fractal.components; 10 | if (arguments.length >= 3) { 11 | context = arguments[1]; 12 | } else if (arguments.length == 2) { 13 | context = null; 14 | } else if (arguments.length == 1) { 15 | throw new Error(`You must provide a component handle to the withContext helper.`); 16 | } 17 | const entity = source.find(handle); 18 | if (!entity) { 19 | throw new Error(`Could not get context for component '${handle}' - component not found.`); 20 | } 21 | const defaultContext = _.cloneDeep( 22 | entity.isComponent ? entity.variants().default().getContext() : entity.getContext() 23 | ); 24 | 25 | return utils.defaultsDeep(context || {}, defaultContext); 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/handlebars/src/helpers/context.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Handlebars = require('handlebars'); 4 | 5 | module.exports = function (fractal) { 6 | return function context(handle) { 7 | const source = fractal.components; 8 | const entity = source.find(handle); 9 | if (!entity) { 10 | throw new Error(`Could not get context for component '${handle}' - component not found.`); 11 | } 12 | const context = entity.isComponent ? entity.variants().default().getContext() : entity.getContext(); 13 | return new Handlebars.SafeString(JSON.stringify(context, null, 4)); 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/handlebars/src/helpers/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (fractal) { 4 | return { 5 | render: require('./render.js')(fractal), 6 | context: require('./context.js')(fractal), 7 | contextData: require('./context-data.js')(fractal), 8 | view: require('./view.js')(fractal), 9 | path: require('./path.js')(fractal), 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/handlebars/src/helpers/view.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Handlebars = require('handlebars'); 4 | 5 | module.exports = function (fractal) { 6 | return function view(handle) { 7 | const source = fractal.components; 8 | let entity = source.find(handle); 9 | if (!entity) { 10 | throw new Error(`Could not get view contents for component '${handle}' - component not found.`); 11 | } 12 | if (entity.isComponent) { 13 | entity = entity.variants().default(); 14 | } 15 | return entity.getContent().then((content) => new Handlebars.SafeString(content)); 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/handlebars/src/partials/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function () { 4 | return { 5 | // none added yet! 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/handlebars/src/partials/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js" 3 | } 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'babel-eslint', 3 | env: { 4 | jquery: true, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/mandelbrot/.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frctl/fractal/dd6cd938653b24cd23456d10b9c28d3bc436c4c3/packages/mandelbrot/assets/favicon.ico -------------------------------------------------------------------------------- /packages/mandelbrot/assets/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frctl/fractal/dd6cd938653b24cd23456d10b9c28d3bc436c4c3/packages/mandelbrot/assets/img/favicon.png -------------------------------------------------------------------------------- /packages/mandelbrot/assets/img/icon-drag--horizontal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/img/icon-drag--vertical.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/img/icon-navigation-closed-ltr.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/img/icon-navigation-closed-rtl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/img/icon-navigation-opened.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/img/icon-window.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/js/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default { 4 | breakpoints: { 5 | navCollapse: 760, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/js/events.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | export default global.jQuery({}); 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/js/storage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const storages = { 4 | local: localStorage, 5 | session: sessionStorage, 6 | }; 7 | 8 | export default { 9 | get(name, fallback, storage = 'local') { 10 | const result = storages[storage].getItem(name); 11 | return result ? JSON.parse(result) : fallback; 12 | }, 13 | 14 | set(name, value, storage = 'local') { 15 | storages[storage].setItem(name, JSON.stringify(value)); 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/js/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import config from './config'; 4 | 5 | export default { 6 | debounce(func, wait, immediate) { 7 | var timeout; 8 | return function () { 9 | var context = this, 10 | args = arguments; 11 | var later = function () { 12 | timeout = null; 13 | if (!immediate) func.apply(context, args); 14 | }; 15 | var callNow = immediate && !timeout; 16 | clearTimeout(timeout); 17 | timeout = setTimeout(later, wait); 18 | if (callNow) func.apply(context, args); 19 | }; 20 | }, 21 | 22 | isSmallScreen() { 23 | return $(document).width() < config.breakpoints.navCollapse; 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/components/_all.scss: -------------------------------------------------------------------------------- 1 | @import "asset-list"; 2 | @import "browser"; 3 | @import "code"; 4 | @import "document"; 5 | @import "error"; 6 | @import "file-browser"; 7 | @import "frame"; 8 | @import "header"; 9 | @import "meta"; 10 | @import "navigation"; 11 | @import "pen"; 12 | @import "preview"; 13 | @import "prose"; 14 | @import "search"; 15 | @import "status"; 16 | @import "tree"; 17 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/components/_asset-list.scss: -------------------------------------------------------------------------------- 1 | .AssetList { 2 | list-style: none; 3 | max-width: 900px; 4 | margin-top: 40px; 5 | } 6 | 7 | .AssetList-asset { 8 | list-style: none; 9 | width: 100%; 10 | } 11 | 12 | .AssetList-name { 13 | color: rgba($color-text, 0.5); 14 | 15 | strong { 16 | --color: rgb(var(--skin-links)); 17 | 18 | color: $color-link; 19 | color: var(--color, $color-link); 20 | font-weight: normal; 21 | } 22 | } 23 | 24 | .AssetList-link { 25 | display: flex; 26 | align-items: center; 27 | width: 100%; 28 | padding: 0.5rem 0; 29 | text-decoration: none; 30 | 31 | &:hover { 32 | .AssetList-path { 33 | color: rgba($color-text, 0.75); 34 | } 35 | 36 | .AssetList-icon { 37 | svg { 38 | fill: #999; 39 | } 40 | } 41 | } 42 | } 43 | 44 | .AssetList-icon { 45 | @include margin-inline(end, 0.5rem); 46 | 47 | svg { 48 | fill: #ccc; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/components/_code.scss: -------------------------------------------------------------------------------- 1 | .Code { 2 | display: block; 3 | background-color: $color-background-offset; 4 | 5 | pre { 6 | padding: 0.75rem; 7 | 8 | a { 9 | color: #28f; 10 | text-decoration: none; 11 | 12 | &:hover { 13 | text-decoration: underline; 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/components/_document.scss: -------------------------------------------------------------------------------- 1 | .Document { 2 | padding: 1.5rem 2rem; 3 | 4 | @include mq($until: nav-collapse) { 5 | padding: 1.25rem 1rem; 6 | } 7 | } 8 | 9 | .Document-header { 10 | display: flex; 11 | width: 100%; 12 | margin-bottom: 1.5rem; 13 | border-bottom: 1px solid $color-frame-border; 14 | padding-bottom: 0.5rem; 15 | 16 | .Status { 17 | @include margin-inline(start, auto); 18 | } 19 | } 20 | 21 | .Document-title { 22 | @include font(title); 23 | } 24 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/components/_error.scss: -------------------------------------------------------------------------------- 1 | .Error-stack { 2 | margin-top: 1.5rem; 3 | 4 | pre { 5 | @include font(code); 6 | 7 | color: rgba($color-text, 0.75); 8 | } 9 | } 10 | 11 | .Error--render { 12 | background-color: rgba(#b00, 0.05); 13 | border: 1px solid rgba(#b00, 0.25); 14 | padding: 0.75rem; 15 | 16 | .Error-title { 17 | @include font(label); 18 | 19 | color: #b00; 20 | } 21 | 22 | .Error-message { 23 | @include font(caption); 24 | } 25 | 26 | .Error-stack { 27 | pre, 28 | code { 29 | background-color: #fff !important; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/components/_search.scss: -------------------------------------------------------------------------------- 1 | .Navigation-search { 2 | padding-left: 1rem; 3 | padding-right: 1rem; 4 | } 5 | 6 | .Search { 7 | position: relative; 8 | } 9 | 10 | .Search-clearButton { 11 | width: 2rem; 12 | height: 100%; 13 | position: absolute; 14 | top: 0; 15 | right: 0; 16 | line-height: 0; 17 | opacity: 0.5; 18 | 19 | &:hover, 20 | &:focus { 21 | opacity: 1; 22 | } 23 | 24 | svg { 25 | width: 18px; 26 | height: 18px; 27 | } 28 | } 29 | 30 | .Search-label { 31 | display: block; 32 | margin-bottom: 0.5rem; 33 | color: $color-sidebar-heading; 34 | 35 | @include font(label); 36 | @include visuallyhidden; 37 | } 38 | 39 | .Search-input { 40 | width: 100%; 41 | padding: 0.3125rem 2rem 0.3125rem 0.5625rem; 42 | appearance: none; 43 | border-radius: 3px; 44 | border: 1px solid $color-frame-border; 45 | line-height: 1.5; 46 | 47 | // Hide native "clear" button in IE 48 | &::-ms-clear { 49 | display: none; 50 | } 51 | 52 | // Hide native clear button in chromium/webkit browsers 53 | &::-webkit-search-cancel-button { 54 | -webkit-appearance: none; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/components/_status.scss: -------------------------------------------------------------------------------- 1 | .Status, 2 | .Status-dots { 3 | display: flex; 4 | align-items: center; 5 | } 6 | 7 | .Status-dot { 8 | width: 0.5rem; 9 | height: 0.5rem; 10 | background-color: white; 11 | border: 1px solid transparent; 12 | border-radius: 100%; 13 | } 14 | 15 | .Status-dot + .Status-dot { 16 | @include margin-inline(start, 3px); 17 | } 18 | 19 | .Status-label { 20 | @include font(label); 21 | 22 | display: inline-block; 23 | border-radius: 2rem; 24 | padding: 0.125rem 0.75rem; 25 | color: white; 26 | white-space: nowrap; 27 | } 28 | 29 | .Status-label + .Status-label { 30 | @include margin-inline(start, 0.25rem); 31 | } 32 | 33 | .Status--labelled { 34 | .Status-label { 35 | @include margin-inline(end, 0.75rem); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/core/_all.scss: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Config 3 | // ----------------------------------------------------------------------------- 4 | 5 | $width-sidebar: 240px; 6 | $handle-size: 0.625rem; 7 | 8 | $mq-breakpoints: ( 9 | nav-collapse: 760px, 10 | medium: 600px, 11 | large: 800px, 12 | ); 13 | 14 | // ----------------------------------------------------------------------------- 15 | // Vendor (node_modules) 16 | // ----------------------------------------------------------------------------- 17 | 18 | @import "normalize.css/normalize"; 19 | @import "sass-mq/_mq"; 20 | 21 | // ----------------------------------------------------------------------------- 22 | // Core 23 | // ----------------------------------------------------------------------------- 24 | 25 | @import "mixins"; 26 | @import "foundation"; 27 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/highlight.scss: -------------------------------------------------------------------------------- 1 | @import "highlight.js/styles/github"; 2 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/aqua.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #7df; 2 | $color-header-content: #035; 3 | $color-link: #06a; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/black.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #111; 2 | $color-header-content: #fff; 3 | $color-link: #28f; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/blue.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #14f; 2 | $color-header-content: #fff; 3 | $color-link: #28f; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/default.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #14f; 2 | $color-header-content: #fff; 3 | $color-link: #28f; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/fuchsia.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #f2d; 2 | $color-header-content: #402; 3 | $color-link: #a06; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/green.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #3c4; 2 | $color-header-content: #fff; 3 | $color-link: #172; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/grey.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #bbb; 2 | $color-header-content: #111; 3 | $color-link: #28f; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/lime.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #bd2; 2 | $color-header-content: #330; 3 | $color-link: #670; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/maroon.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #804; 2 | $color-header-content: #fde; 3 | $color-link: #402; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/navy.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #024; 2 | $color-header-content: #def; 3 | $color-link: #048; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/olive.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #276; 2 | $color-header-content: #efd; 3 | $color-link: #054; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/orange.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #f82; 2 | $color-header-content: #510; 3 | $color-link: #840; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/purple.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #a0c; 2 | $color-header-content: #fff; 3 | $color-link: #608; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/red.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #f43; 2 | $color-header-content: #fff; 3 | $color-link: #822; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/teal.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #3dd; 2 | $color-header-content: #033; 3 | $color-link: #066; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/white.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #eee; 2 | $color-header-content: #111; 3 | $color-link: #28f; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/skins/yellow.scss: -------------------------------------------------------------------------------- 1 | $color-header-background: #fd0; 2 | $color-header-content: #530; 3 | $color-link: #a60; 4 | 5 | @import "../theme"; 6 | @import "../core/all"; 7 | @import "../components/all"; 8 | -------------------------------------------------------------------------------- /packages/mandelbrot/assets/scss/theme.scss: -------------------------------------------------------------------------------- 1 | $font-family-monospace: "SFMono-Regular", "Consolas", "Liberation Mono", "Menlo", monospace !default; 2 | $font-family-sans-serif: "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Helvetica", "Arial", sans-serif, 3 | "Apple Color Emoji", "Segoe UI Emoji" !default; 4 | 5 | $color-link: #28f !default; 6 | $color-text: #535363 !default; 7 | $color-heading: #444 !default; 8 | 9 | $color-background: #fff !default; 10 | $color-background-offset: #f6f6f6 !default; 11 | 12 | $color-ui-hover: rgba($color-text, 0.05) !default; 13 | $color-ui-active: rgba($color-text, 0.075) !default; 14 | 15 | $color-header-background: #14f !default; 16 | $color-header-content: #fff !default; 17 | 18 | $color-frame-border: rgba($color-text, 0.25) !default; 19 | 20 | $color-sidebar-heading: rgba($color-text, 0.75) !default; 21 | 22 | $highlight-theme: "github" !default; 23 | -------------------------------------------------------------------------------- /packages/mandelbrot/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./src/theme'); 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/icons/arrow-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/icons/asset.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/icons/burger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/icons/collapse.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/icons/open-in-browser.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/layouts/doc.nunj: -------------------------------------------------------------------------------- 1 | {% extends "layouts/pjax.nunj" if request.isPjax else "layouts/frame.nunj" %} 2 | 3 | {% block content %} 4 | 5 |
    6 | 7 |
    8 | {% block docHeader %} 9 |

    {{ page.title }}

    10 | {% if status %}{{ status }}{% endif %} 11 | {% endblock %} 12 |
    13 | 14 |
    15 | 16 | {% block docContent %}{% endblock %} 17 | 18 |
    19 | 20 |
    21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/layouts/frame.nunj: -------------------------------------------------------------------------------- 1 | {% extends "layouts/skeleton.nunj" %} 2 | {% import "macros/navigation.nunj" as nav %} 3 | 4 | {% block page %} 5 | 6 |
    7 | 8 |
    9 | {% include 'partials/header.nunj' %} 10 |
    11 | 12 |
    13 | 14 |
    15 |
    16 | {% block content %}{% endblock %} 17 |
    18 |
    19 | 20 |
    21 | {% include 'partials/navigation/navigation.nunj' %} 22 |
    23 |
    24 |
    25 | 26 | {% endblock %} 27 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/layouts/full.nunj: -------------------------------------------------------------------------------- 1 | {% extends "layouts/skeleton.nunj" %} 2 | 3 | {% block page %} 4 | 5 |
    6 | 7 | {% block content %}{% endblock %} 8 | 9 |
    10 | 11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/layouts/pen.nunj: -------------------------------------------------------------------------------- 1 | {% extends "layouts/pjax.nunj" if request.isPjax else "layouts/frame.nunj" %} 2 | {% import "macros/image.nunj" as img %} 3 | {% import "macros/status.nunj" as status %} 4 | {% import "macros/errors.nunj" as errors %} 5 | 6 | {% set page = { 7 | title: entity.title 8 | } %} 9 | 10 | {% set previewUrl = path(frctl.theme.urlFromRoute('preview', {handle: entity.handle})) %} 11 | 12 | {% block content %} 13 | 14 |
    15 | 16 | {% block penContent %} 17 | 18 | {% include "partials/pen/header.nunj" %} 19 | 20 | {% include "partials/pen/preview.nunj" %} 21 | 22 |
    23 | 24 | {% include "partials/pen/browser.nunj" %} 25 | 26 | {% endblock %} 27 | 28 |
    29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/layouts/pjax.nunj: -------------------------------------------------------------------------------- 1 |
    2 | {% block content %}{% endblock %} 3 |
    4 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/layouts/render.nunj: -------------------------------------------------------------------------------- 1 | {% if not entity %}{{ throw(404, "Component '" + request.params.handle + "' not found.") }}{% endif -%} 2 | 3 | {% set rendered = entity.render(null, renderEnv, { preview: withLayout, collate: withCollation }) | async(true) %} 4 | 5 | {% if rendered | isError -%} 6 | {% extends 'layouts/full.nunj' %} 7 | {% set error = rendered %} 8 | {% set page = { 9 | title: 'Error rendering component ' + request.params.handle 10 | } %} 11 | {% block content -%}{% import "macros/errors.nunj" as errors -%}{{ errors.renderError('component', error.message, error.stack) }}{% endblock %} 12 | {%- else -%} 13 | {{ rendered }} 14 | {%- endif %} 15 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/layouts/skeleton.nunj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | {% include 'partials/head.nunj' %} 13 | 14 | 15 | 16 | {% block page %}{% endblock %} 17 | 18 | {% include 'partials/foot.nunj' %} 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/macros/errors.nunj: -------------------------------------------------------------------------------- 1 | {% macro renderError(type, message, stack) %} 2 |
    3 |

    Error rendering {{ type }}

    4 |
    5 | {{ message | markdown }} 6 |
    7 | {% if stack %} 8 | 9 |
    {{ stack }}
    10 |
    11 | {% endif %} 12 |
    13 | {% endmacro %} 14 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/macros/image.nunj: -------------------------------------------------------------------------------- 1 | {% macro svg(name, fill='#222', width='20px', height='20px', viewbox='0 0 320 320') %} 2 | 3 | {% include 'icons/' + name + '.nunj' %} 4 | 5 | {% endmacro %} 6 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/macros/render.nunj: -------------------------------------------------------------------------------- 1 | {% macro entity(rendered) %} 2 | {% if rendered | isError %} 3 | {% set renderError %} 4 | 5 | 6 | 7 | {% endset %} 8 | {{ renderError | highlight('html') }} 9 | {% else %} 10 | {{ rendered | beautify | highlight('html') }} 11 | {% endif %} 12 | {% endmacro %} 13 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/pages/assets.nunj: -------------------------------------------------------------------------------- 1 | {% extends "layouts/doc.nunj" %} 2 | 3 | {% set assetSource = frctl.assets.find(request.params.name) %} 4 | {% if not assetSource or assetSource.isHidden %}{{ throw(404, 'Asset source not found') }}{% endif %} 5 | 6 | {% set page = { 7 | title: assetSource.title 8 | } %} 9 | 10 | {% block docContent %} 11 | 12 | {% if assetSource.notes %} 13 |
    14 | {{ frctl.docs.renderString(assetSource.notes) | async }} 15 |
    16 | {% endif %} 17 | 18 | 30 | 31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/pages/components/detail.nunj: -------------------------------------------------------------------------------- 1 | {% extends "layouts/pen.nunj" %} 2 | 3 | {% set entity = frctl.components.find('@' + request.params.handle) %} 4 | {% if not entity %}{{ throw(404, "Component '" + request.params.handle + "' not found.") }}{% endif %} 5 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/pages/components/preview.nunj: -------------------------------------------------------------------------------- 1 | {% extends 'layouts/render.nunj' %} 2 | 3 | {% set entity = frctl.components.find('@' + request.params.handle) -%} 4 | {% set withLayout = true -%} 5 | {% set withCollation = true -%} 6 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/pages/components/render.nunj: -------------------------------------------------------------------------------- 1 | {% extends 'layouts/render.nunj' %} 2 | 3 | {% set entity = frctl.components.find('@' + request.params.handle) -%} 4 | {% set withLayout = false -%} 5 | {% set withCollation = true -%} 6 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/pages/doc.nunj: -------------------------------------------------------------------------------- 1 | {% extends "layouts/doc.nunj"%} 2 | {% import "macros/status.nunj" as status %} 3 | 4 | {% set pathParam = request.params.path %} 5 | {% set doc = frctl.docs.find('path', pathParam | default('')) %} 6 | 7 | {% if pathParam and not doc %}{{ throw(404, 'Page not found') }}{% endif %} 8 | 9 | {% set page = { 10 | title: doc.title | default(frctl.get('project.title')) | default('Welcome to your component library') 11 | } %} 12 | 13 | {% set status = status.tag(doc.status) %} 14 | 15 | {% block docContent %} 16 | 17 |
    18 | {% block pageContent %} 19 | {% import "macros/errors.nunj" as errors %} 20 | {% if doc %} 21 | {% set contents = doc.render(null, renderEnv) | async(true) %} 22 | {% if contents | isError %} 23 | {{ errors.renderError('page', contents.message) }} 24 | {% else %} 25 | {{ contents }} 26 | {% endif %} 27 | {% else %} 28 | {% include 'partials/content/overview.nunj' %} 29 | {% endif %} 30 | {% endblock %} 31 |
    32 | 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/pages/error.nunj: -------------------------------------------------------------------------------- 1 | {% extends "layouts/doc.nunj" %} 2 | 3 | {% set page = { 4 | title: ('Not found' if error.status == '404' else error.name) | default('An error has occurred') 5 | } %} 6 | 7 | {% block docContent %} 8 | 9 |
    10 | 11 |
    12 | {{ error.message | default('No more information is available.') | markdown }} 13 |
    14 | 15 | {% if error.stack and error.status != '404' %} 16 | 17 |
    {{ error.stack }}
    18 |
    19 | {% endif %} 20 | 21 |
    22 | 23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/browser/browser.nunj: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {% include 'partials/browser/controls.nunj' %} 4 | 5 | {% asyncAll panel in frctl.theme.get('panels') %} 6 | {% include 'partials/browser/panel-' + panel + '.nunj' %} 7 | {% endall %} 8 | 9 |
    10 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/browser/controls.nunj: -------------------------------------------------------------------------------- 1 | {% import "macros/image.nunj" as img %} 2 | 3 |
    4 | 23 |
    24 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/browser/panel-html.nunj: -------------------------------------------------------------------------------- 1 | {% import "macros/render.nunj" as render %} 2 |
    3 | 4 | {% if not entity.isCollated or entity.isVariant or entity.variants().size == 1 %} 5 |
    {{ render.entity(entity.render(null, renderEnv, {preview: false, collate: false}) | async(true)) | trim }}
    6 | {% else %} 7 | {% for variant in entity.variants().items() %} 8 |
    {{ '<!-- ' + variant.label + ' -->' }}
     9 | {{ render.entity(variant.render(null, renderEnv, {preview: false, collate: false}) | async(true)) | trim }}
    10 | 
    11 | 
    12 | {% endfor %} 13 | {% endif %} 14 |
    15 |
    16 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/browser/panel-notes.nunj: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | {% if entity.notes %} 4 | {{ frctl.docs.renderString(entity.notes, null, renderEnv) | async }} 5 | {% else %} 6 |

    {{ frctl.theme.get('labels.components.notes.empty') }}

    7 | {% endif %} 8 |
    9 |
    10 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/browser/panel-view.nunj: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    {{ entity.getPreviewContent() | async | trim | highlight(entity.editorMode | default(entity.lang)) | linkRefs(entity) }}
    4 |
    5 |
    6 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/content/overview.nunj: -------------------------------------------------------------------------------- 1 | {% import "macros/status.nunj" as status %} 2 | 3 |

    You can browse the component library using the navigation on the left.

    4 | 5 |

    Component statuses

    6 |

    Components and their variants have been given statuses reflecting their state of completion. The available statuses are listed below.

    7 | 8 | 9 | 10 | 11 | 12 | {% for handle, st in frctl.get('components.statuses') %} 13 | 14 | 15 | 16 | 17 | {% endfor %} 18 |
    LabelDescription
    {{ status.tag(st) }}{{ st.description }}
    19 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/foot.nunj: -------------------------------------------------------------------------------- 1 | {% include 'partials/scripts.nunj' %} 2 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/head.nunj: -------------------------------------------------------------------------------- 1 | 2 | {% include 'partials/stylesheets.nunj' %} 3 | {% if page.title %}{{ page.title }} | {% endif %}{{ frctl.get('project.title') }} 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/header.nunj: -------------------------------------------------------------------------------- 1 |
    2 | 10 | {{ frctl.get('project.title') | default('Component Library') }} 11 |
    12 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/navigation/assets.nunj: -------------------------------------------------------------------------------- 1 | {% if frctl.assets.visible().length %} 2 | 18 | {% endif %} 19 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/navigation/components.nunj: -------------------------------------------------------------------------------- 1 | {% set rootCollections = frctl.components.rootCollections().filter('isHidden', false) %} 2 | {% for collection in rootCollections %} 3 | {# collection must have either entities (non-collection items) or non-root collections #} 4 | {% if collection.entities().size > 0 or collection.collections().filterAll('isRoot', false).size > 0 %} 5 | 8 | {% endif %} 9 | {% endfor %} 10 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/navigation/docs.nunj: -------------------------------------------------------------------------------- 1 | {% if frctl.docs.size %} 2 | 5 | {% endif %} 6 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/navigation/information.nunj: -------------------------------------------------------------------------------- 1 | {% if frctl.theme.get('information').length %} 2 | 27 | {% endif %} 28 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/navigation/search.nunj: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/navigation/variants.nunj: -------------------------------------------------------------------------------- 1 | {% if frctl.components.size %} 2 | {% for item in frctl.components.flatten() %} 3 | {% if item.variants().filter('isHidden', false).size > 1 %} 4 | {% set isVisible = true if (entity and ((entity.id == item.id) or entity.parent.id == item.id)) else false %} 5 | 8 | {% endif %} 9 | {% endfor %} 10 | {% endif %} 11 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/pen/browser.nunj: -------------------------------------------------------------------------------- 1 |
    2 | {% include 'partials/browser/browser.nunj' %} 3 |
    4 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/pen/header.nunj: -------------------------------------------------------------------------------- 1 |
    2 |

    3 | 4 | {{ entity.title }} 5 | {% include "icons/open-in-browser.svg" %} 6 | 7 |

    8 | 9 | 10 | 11 | {{ status.tag(entity.status) }} 12 |
    13 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/pen/preview.nunj: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | 11 |
    12 |
    13 |
    14 |
    15 |
    16 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/scripts.nunj: -------------------------------------------------------------------------------- 1 | {% for script in frctl.theme.get('scripts') %} 2 | 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /packages/mandelbrot/views/partials/stylesheets.nunj: -------------------------------------------------------------------------------- 1 | 14 | {% for stylesheet in frctl.theme.get('styles') %} 15 | 16 | {% endfor %} 17 | -------------------------------------------------------------------------------- /packages/nunjucks/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./src/adapter'); 4 | -------------------------------------------------------------------------------- /packages/nunjucks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/nunjucks", 3 | "version": "2.0.15", 4 | "description": "Nunjucks template adapter for Fractal.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/frctl/fractal.git", 9 | "directory": "packages/nunjucks" 10 | }, 11 | "author": "Mark Perkins (http://clearleft.com/)", 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/frctl/fractal/issues" 15 | }, 16 | "homepage": "https://github.com/frctl/fractal/tree/main/packages/nunjucks", 17 | "peerDependencies": { 18 | "@frctl/fractal": ">= 1.1.0-alpha.0 < 2" 19 | }, 20 | "dependencies": { 21 | "@frctl/core": "^0.3.5", 22 | "bluebird": "^3.7.2", 23 | "lodash": "^4.17.21", 24 | "nunjucks": "^3.2.3" 25 | }, 26 | "publishConfig": { 27 | "access": "public" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/nunjucks/src/extensions/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (fractal) { 4 | return { 5 | render: require('./render.js')(fractal), 6 | view: require('./view.js')(fractal), 7 | context: require('./context.js')(fractal), 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/nunjucks/src/filters/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (fractal) { 4 | return { 5 | path: require('./path.js')(fractal), 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/nunjucks/src/filters/path.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const utils = require('@frctl/core').utils; 5 | 6 | module.exports = function (fractal) { 7 | return function (path) { 8 | let env = this.lookup('_env'); 9 | let request = env.request || this.lookup('_request') || this.ctx.request; 10 | 11 | return !env || env.server 12 | ? path 13 | : utils.relUrlPath(path, _.get(request, 'path', '/'), fractal.web.get('builder.urls')); 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/react/components/index.d.ts: -------------------------------------------------------------------------------- 1 | export interface PathContext { 2 | get: (path: string) => string; 3 | } 4 | 5 | export interface PathProviderProps extends PathContext { 6 | children: React.ReactNode; 7 | } 8 | 9 | export const PathProvider: React.ComponentType 10 | export const PathContext: React.Context; 11 | export const usePath: () => PathContext; 12 | -------------------------------------------------------------------------------- /packages/react/components/index.js: -------------------------------------------------------------------------------- 1 | const PathProvider = require('./path-provider'); 2 | 3 | module.exports = { 4 | PathProvider: PathProvider, 5 | PathContext: PathProvider.PathContext, 6 | usePath: PathProvider.usePath, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/react/components/path-provider.js: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | const PropTypes = require('prop-types'); 3 | 4 | const PathContext = React.createContext({ 5 | get: (path) => path, 6 | }); 7 | 8 | const PathProvider = (props) => { 9 | const { children, ...rest } = props; 10 | 11 | return React.createElement(PathContext.Provider, { value: rest }, children); 12 | }; 13 | 14 | PathProvider.propTypes = { 15 | children: PropTypes.node, 16 | get: PropTypes.func, 17 | }; 18 | 19 | const usePath = () => { 20 | return React.useContext(PathContext); 21 | }; 22 | 23 | module.exports = PathProvider; 24 | module.exports.PathContext = PathContext; 25 | module.exports.usePath = usePath; 26 | -------------------------------------------------------------------------------- /packages/react/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./src/adapter'); 4 | -------------------------------------------------------------------------------- /packages/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/react", 3 | "version": "0.3.7", 4 | "description": "React template adapter for Fractal.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/frctl/fractal.git", 9 | "directory": "packages/react" 10 | }, 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/frctl/fractal/issues" 14 | }, 15 | "homepage": "https://github.com/frctl/fractal/tree/main/packages/react", 16 | "dependencies": { 17 | "@babel/core": "^7.14.0", 18 | "@babel/preset-env": "^7.14.1", 19 | "@babel/preset-react": "^7.13.13", 20 | "@babel/register": "^7.13.16", 21 | "@frctl/core": "^0.3.5", 22 | "lodash": "^4.17.21", 23 | "parent-module": "^2.0.0", 24 | "prop-types": "^15.7.2", 25 | "resolve-from": "^5.0.0" 26 | }, 27 | "devDependencies": { 28 | "react": "^17.0.2", 29 | "react-dom": "^17.0.2" 30 | }, 31 | "peerDependencies": { 32 | "@frctl/fractal": ">= 1.1.7 < 2", 33 | "react": ">= 16.8.0 < 18", 34 | "react-dom": ">= 16.8.0 < 18" 35 | }, 36 | "publishConfig": { 37 | "access": "public" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/twig/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./src/adapter'); 4 | -------------------------------------------------------------------------------- /packages/twig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/twig", 3 | "version": "1.2.13", 4 | "description": "Twig template adapter for Fractal.", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/frctl/fractal.git", 9 | "directory": "packages/twig" 10 | }, 11 | "author": "Mark Perkins (http://clearleft.com/)", 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/frctl/fractal/issues" 15 | }, 16 | "homepage": "https://github.com/frctl/fractal/tree/main/packages/twig", 17 | "dependencies": { 18 | "@frctl/core": "^0.3.5", 19 | "lodash": "^4.17.21", 20 | "twig": "^1.15.4" 21 | }, 22 | "peerDependencies": { 23 | "@frctl/fractal": "^1.1.0-beta.1" 24 | }, 25 | "publishConfig": { 26 | "access": "public" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/twig/src/filters/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (fractal) { 4 | return { 5 | path: require('./path.js')(fractal), 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/twig/src/filters/path.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const utils = require('@frctl/core').utils; 5 | 6 | module.exports = function (fractal) { 7 | return function (path) { 8 | let env = this.context._env; 9 | if (!env || env.server) { 10 | return path; 11 | } 12 | 13 | let request = env.request || this.context._request; 14 | return utils.relUrlPath(path, _.get(request, 'path', '/'), fractal.web.get('builder.urls')); 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/twig/src/functions/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function () { 4 | return {}; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/twig/src/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js" 3 | } 4 | -------------------------------------------------------------------------------- /packages/twig/src/tags/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (fractal, config) { 4 | return { 5 | render: require('./render.js')(fractal, config), 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/twig/src/tests/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function () { 4 | return {}; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/twig/src/tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js" 3 | } 4 | -------------------------------------------------------------------------------- /packages/twig/src/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | isHandle(str, handlePrefix) { 5 | return str && str.startsWith(handlePrefix); 6 | }, 7 | replaceHandlePrefix(handle, handlePrefix) { 8 | let prefixMatcher = new RegExp(`^\\${handlePrefix}`); 9 | 10 | return handle.replace(prefixMatcher, '@'); 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/web/README.md: -------------------------------------------------------------------------------- 1 | # @frctl/web 2 | 3 | The web module of [Fractal](http://github.com/frctl/fractal). 4 | 5 | [![NPM Version](https://img.shields.io/npm/v/@frctl/web)](https://www.npmjs.com/package/@frctl/web) 6 | 7 | ## License 8 | 9 | [MIT](https://github.com/frctl/fractal/blob/main/LICENSE) 10 | -------------------------------------------------------------------------------- /packages/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@frctl/web", 3 | "version": "0.1.12", 4 | "description": "Web module of Fractal.", 5 | "main": "src/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/frctl/fractal.git", 9 | "directory": "packages/web" 10 | }, 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/frctl/fractal/issues" 14 | }, 15 | "homepage": "https://github.com/frctl/fractal/tree/main/packages/web", 16 | "dependencies": { 17 | "@frctl/core": "^0.3.5", 18 | "anymatch": "^3.1.2", 19 | "bluebird": "^3.7.2", 20 | "browser-sync": "^2.26.14", 21 | "chokidar": "^3.5.1", 22 | "express": "^4.17.1", 23 | "fs-extra": "^9.1.0", 24 | "get-port": "^5.1.1", 25 | "js-yaml": "^4.1.0", 26 | "lodash": "^4.17.21", 27 | "nunjucks": "^3.2.3", 28 | "path-to-regexp": "^6.2.0", 29 | "require-all": "^3.0.0", 30 | "throat": "^6.0.1" 31 | }, 32 | "publishConfig": { 33 | "access": "public" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/web/src/engine/extensions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frctl/fractal/dd6cd938653b24cd23456d10b9c28d3bc436c4c3/packages/web/src/engine/extensions/.gitkeep -------------------------------------------------------------------------------- /packages/web/src/engine/filters/async.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Promise = require('bluebird'); 4 | 5 | module.exports = function () { 6 | return { 7 | name: 'async', 8 | async: true, 9 | filter() { 10 | const args = Array.from(arguments); 11 | const cb = args.pop(); 12 | if (!args[1]) { 13 | Promise.resolve(args[0]) 14 | .then((result) => cb(null, result)) 15 | .catch(cb); 16 | } else { 17 | Promise.resolve(args[0]) 18 | .then((result) => cb(null, result)) 19 | .catch((e) => { 20 | cb(null, e); 21 | return e; 22 | }); 23 | } 24 | }, 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/web/src/engine/filters/format.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const yaml = require('js-yaml'); 5 | 6 | module.exports = function () { 7 | return { 8 | name: 'format', 9 | filter(obj, format) { 10 | format = (format || 'json').toLowerCase(); 11 | if (_.isString(obj)) { 12 | return obj; 13 | } 14 | if (obj instanceof Buffer) { 15 | return obj.toString('UTF-8'); 16 | } 17 | if (format === 'yaml' || format === 'yml') { 18 | return yaml.dump(obj); 19 | } 20 | if (format === 'json') { 21 | return JSON.stringify(obj, null, 2); 22 | } 23 | throw new Error(`Unknown format: ${format}`); 24 | }, 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /packages/web/src/engine/filters/highlight.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (app) { 4 | return { 5 | name: 'highlight', 6 | filter: (str, lang) => app.get('web.highlighter')(str, lang), 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/web/src/engine/filters/is-error.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function () { 4 | return { 5 | name: 'isError', 6 | filter(item) { 7 | return item instanceof Error; 8 | }, 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/web/src/engine/filters/markdown.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const markdown = require('@frctl/core').markdown; 4 | 5 | module.exports = function () { 6 | return { 7 | name: 'markdown', 8 | filter: (str) => markdown(str), 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/web/src/engine/filters/render.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (app, engine) { 4 | return { 5 | name: 'render', 6 | async: false, 7 | filter: (str, context) => engine.renderString(str, context || {}), 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/web/src/engine/globals/dump.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function () { 4 | return { 5 | name: 'dump', 6 | value(obj, preformat) { 7 | preformat = preformat === false ? false : true; 8 | const output = JSON.stringify(obj, null, 4); 9 | return preformat ? '
    ' + output + '
    ' : output; 10 | }, 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /packages/web/src/engine/globals/log.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (app) { 4 | return { 5 | name: 'log', 6 | value(item, type) { 7 | app.cli.console[type || 'log'](item); 8 | }, 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/web/src/engine/globals/path.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const utils = require('@frctl/core').utils; 5 | 6 | module.exports = function (app, engine) { 7 | return { 8 | name: 'path', 9 | value(path, req) { 10 | req = req || this.lookup('request'); 11 | return engine.env === 'server' 12 | ? path 13 | : utils.relUrlPath(path, _.get(req, 'path', '/'), app.web.get('builder.urls')); 14 | }, 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/web/src/engine/globals/static.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function () { 4 | return { 5 | name: 'static', 6 | value(path) { 7 | return path; 8 | }, 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/web/src/engine/globals/throw.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const WebError = require('../../error'); 4 | 5 | module.exports = function () { 6 | return { 7 | name: 'throw', 8 | value(code, message) { 9 | code = code || 500; 10 | throw new WebError(code, message || `${code} error`); 11 | }, 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/web/src/engine/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./engine'); 2 | -------------------------------------------------------------------------------- /packages/web/src/error.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class WebError extends Error { 4 | constructor(statusCode, message) { 5 | statusCode = (statusCode || '500').toString(); 6 | message = message || `${statusCode} error`; 7 | super(message); 8 | this.name = 'Web Error'; 9 | this.status = statusCode; 10 | this.code = statusCode; 11 | this.message = message; 12 | if (typeof Error.captureStackTrace === 'function') { 13 | Error.captureStackTrace(this, this.constructor); 14 | } else { 15 | this.stack = new Error(message).stack; 16 | } 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /packages/web/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Builder: require('./builder'), 3 | Engine: require('./engine'), 4 | Server: require('./server'), 5 | Theme: require('./theme'), 6 | Web: require('./web'), 7 | WebError: require('./error'), 8 | }; 9 | -------------------------------------------------------------------------------- /packages/web/test/server.spec.js: -------------------------------------------------------------------------------- 1 | const app = require('../../fractal/src/fractal')(); 2 | 3 | const Theme = require('../src/theme'); 4 | 5 | const Server = require('../src/server'); 6 | 7 | describe('Server', () => { 8 | let server; 9 | 10 | beforeEach(() => { 11 | server = new Server(new Theme(), {}, app); 12 | }); 13 | 14 | it('is an event emitter', () => { 15 | expect(server.hasMixedIn('Emitter')).toBe(true); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/web/test/web.spec.js: -------------------------------------------------------------------------------- 1 | const app = require('../../fractal/src/fractal')(); 2 | 3 | const Web = require('../src/web'); 4 | 5 | describe('Web', () => { 6 | let web; 7 | 8 | beforeEach(() => { 9 | web = new Web(app); 10 | }); 11 | 12 | it('is an event emitter', () => { 13 | expect(web.hasMixedIn('Emitter')).toBe(true); 14 | }); 15 | it('is configurable', () => { 16 | expect(web.hasMixedIn('Configurable')).toBe(true); 17 | }); 18 | 19 | describe('.serve()', () => { 20 | it.todo('starts a web server'); 21 | }); 22 | 23 | describe('.build()', () => { 24 | it.todo('starts the static build process'); 25 | }); 26 | 27 | describe('.theme()', () => { 28 | it.todo('adds a theme'); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/web/views/__system/error.nunj: -------------------------------------------------------------------------------- 1 | {% extends '__system/skeleton.nunj' %} 2 | 3 | {% set page = { 4 | type: 'error', 5 | title: 'Not found' if frctl.error.status == '404' else frctl.error.name 6 | } %} 7 | 8 | {% block body %} 9 |
    10 | 11 |
    12 | {{ frctl.error.message | markdown }} 13 |
    14 | 15 | {% if frctl.error.stack and frctl.error.status != '404' %} 16 | 17 |
    {{ frctl.error.stack }}
    18 |
    19 | {% endif %} 20 | 21 |
    22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /packages/web/views/__system/index.nunj: -------------------------------------------------------------------------------- 1 | {% extends '__system/skeleton.nunj' %} 2 | 3 | {% set page = { 4 | title: 'Your Fractal project server is up and running!' 5 | } %} 6 | 7 | {% block body %} 8 | 9 |

    It looks like you probably need to install a theme.

    10 | 11 |

    If you are developing your own theme and are seeing this message, then you need to register a route handler for the homepage.

    12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /packages/web/views/__system/redirect.nunj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Redirecting… 7 | 8 | 9 | 10 |

    Redirecting to {{ redirectUrl }} …

    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | singleQuote: true, 4 | printWidth: 120, 5 | tabWidth: 4, 6 | overrides: [ 7 | { 8 | files: ['*.json', '*.yml'], 9 | options: { 10 | tabWidth: 2, 11 | }, 12 | }, 13 | { 14 | files: ['*.scss'], 15 | options: { 16 | singleQuote: false, 17 | }, 18 | }, 19 | ], 20 | }; 21 | -------------------------------------------------------------------------------- /tests/setup.js: -------------------------------------------------------------------------------- 1 | import 'regenerator-runtime/runtime'; 2 | import 'jest-extended'; 3 | --------------------------------------------------------------------------------