@gouvfr/dsfr-roller 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +11 -0
  3. package/index.js +5 -0
  4. package/package.json +65 -0
  5. package/src/component/component.js +50 -0
  6. package/src/component/components/action.js +28 -0
  7. package/src/component/components/breadcrumb.js +33 -0
  8. package/src/component/components/button.js +37 -0
  9. package/src/component/components/display-body.js +41 -0
  10. package/src/component/components/display-modal.js +29 -0
  11. package/src/component/components/footer.js +85 -0
  12. package/src/component/components/header.js +96 -0
  13. package/src/component/components/navigation.js +72 -0
  14. package/src/component/components/sidemenu.js +58 -0
  15. package/src/component/components/skiplink.js +49 -0
  16. package/src/component/components/translate.js +32 -0
  17. package/src/component/components/version.js +21 -0
  18. package/src/component/ejs/version/version.ejs +46 -0
  19. package/src/component/ejs/version/versions.ejs +31 -0
  20. package/src/component/ejs-pkg.js +6 -0
  21. package/src/component/render.js +19 -0
  22. package/src/constants.js +7 -0
  23. package/src/core/format-html.js +16 -0
  24. package/src/core/format-link.js +8 -0
  25. package/src/core/html-renderable.js +10 -0
  26. package/src/core/renderable.js +20 -0
  27. package/src/integration/bundler.js +47 -0
  28. package/src/integration/indexing/indexer.js +23 -0
  29. package/src/integration/indexing/sitemap.js +44 -0
  30. package/src/integration/redirect/redirection-type.js +4 -0
  31. package/src/integration/redirect/redirection.js +77 -0
  32. package/src/node/custom/html-container-node.js +7 -0
  33. package/src/node/directive/doc/accordion-container-directive.js +59 -0
  34. package/src/node/directive/doc/accordions-group-container-directive.js +12 -0
  35. package/src/node/directive/doc/anatomy-container-directive.js +61 -0
  36. package/src/node/directive/doc/button-leaf-directive.js +37 -0
  37. package/src/node/directive/doc/changelog-leaf-directive.js +238 -0
  38. package/src/node/directive/doc/figma-leaf-directive.js +21 -0
  39. package/src/node/directive/doc/guideline-container-directive.js +71 -0
  40. package/src/node/directive/doc/guidelines-container-directive.js +13 -0
  41. package/src/node/directive/doc/image-text-directive.js +13 -0
  42. package/src/node/directive/doc/pin-leaf-directive.js +46 -0
  43. package/src/node/directive/doc/storybook-leaf-directive.js +18 -0
  44. package/src/node/directive/doc/tab-container-directive.js +22 -0
  45. package/src/node/directive/doc/tab-navigation-container-directive.js +49 -0
  46. package/src/node/directive/doc/table-container-directive.js +56 -0
  47. package/src/node/directive/doc/tabs-container-directive.js +71 -0
  48. package/src/node/generic/blockquote-node.js +26 -0
  49. package/src/node/generic/break-node.js +11 -0
  50. package/src/node/generic/code-node.js +37 -0
  51. package/src/node/generic/definition-node.js +13 -0
  52. package/src/node/generic/emphasis-node.js +11 -0
  53. package/src/node/generic/heading-node.js +56 -0
  54. package/src/node/generic/html-node.js +11 -0
  55. package/src/node/generic/image-node.js +14 -0
  56. package/src/node/generic/image-reference-node.js +14 -0
  57. package/src/node/generic/inline-code-node.js +21 -0
  58. package/src/node/generic/link-node.js +26 -0
  59. package/src/node/generic/link-reference-node.js +14 -0
  60. package/src/node/generic/list-item-node.js +11 -0
  61. package/src/node/generic/list-node.js +15 -0
  62. package/src/node/generic/paragraph-node.js +11 -0
  63. package/src/node/generic/strong-node.js +11 -0
  64. package/src/node/generic/text-node.js +15 -0
  65. package/src/node/generic/thematic-break-node.js +12 -0
  66. package/src/node/gfm/table-body-node.js +11 -0
  67. package/src/node/gfm/table-cell-node.js +17 -0
  68. package/src/node/gfm/table-head-node.js +11 -0
  69. package/src/node/gfm/table-header-node.js +16 -0
  70. package/src/node/gfm/table-node.js +91 -0
  71. package/src/node/gfm/table-row-node.js +11 -0
  72. package/src/node/node-factory.js +128 -0
  73. package/src/node/node-root.js +25 -0
  74. package/src/node/node.js +106 -0
  75. package/src/page/body/custom-header.js +40 -0
  76. package/src/page/body/main.js +23 -0
  77. package/src/page/body/scheme.js +9 -0
  78. package/src/page/head/canonical.js +16 -0
  79. package/src/page/head/favicon.js +14 -0
  80. package/src/page/head/head.js +35 -0
  81. package/src/page/head/share.js +14 -0
  82. package/src/page/head/stylesheets.js +48 -0
  83. package/src/page/head/title.js +9 -0
  84. package/src/page/html.js +46 -0
  85. package/src/page/page.js +39 -0
  86. package/src/page/scripts/highlight.js +53 -0
  87. package/src/page/scripts/scripts.js +57 -0
  88. package/src/script/main/core/element.js +29 -0
  89. package/src/script/main/elements/copy-snippet.js +35 -0
  90. package/src/script/main/elements/searchbar.js +18 -0
  91. package/src/script/main/elements/storybook.js +20 -0
  92. package/src/script/main/index.js +10 -0
  93. package/src/script/search/index.js +0 -0
  94. package/src/style/main/components/_dsfr-doc-anatomy.scss +54 -0
  95. package/src/style/main/components/_dsfr-doc-code-snippet.scss +9 -0
  96. package/src/style/main/components/_dsfr-doc-figma-leaf.scss +6 -0
  97. package/src/style/main/components/_dsfr-doc-guideline.scss +58 -0
  98. package/src/style/main/components/_dsfr-doc-tab-navigation.scss +99 -0
  99. package/src/style/main/components/_dsfr-doc-version.scss +154 -0
  100. package/src/style/main/components/_index.scss +6 -0
  101. package/src/style/main/index.scss +3 -0
  102. package/src/style/main/third-party/_highlight.scss +227 -0
  103. package/src/style/main/third-party/_index.scss +1 -0
  104. package/src/style/main/utility/_dsfr-doc-code.scss +9 -0
  105. package/src/style/main/utility/_font.scss +31 -0
  106. package/src/style/main/utility/_icon.scss +4 -0
  107. package/src/style/main/utility/_index.scss +3 -0
  108. package/src/style/search/index.scss +0 -0
  109. package/src/template/template-factory.js +16 -0
  110. package/src/template/template.js +27 -0
  111. package/src/template/templates/editorial-template.js +45 -0
  112. package/src/template/templates/home-template.js +18 -0
  113. package/src/template/templates/search-template.js +20 -0
@@ -0,0 +1,32 @@
1
+ import { Component } from '../component.js';
2
+
3
+ class Translate extends Component {
4
+ constructor (data) {
5
+ super(data, 'translate');
6
+ }
7
+ get ejsPath () {
8
+ return 'src/dsfr/component/translate/template/ejs/translate.ejs';
9
+ }
10
+
11
+ async format () {
12
+ return {
13
+ id: 'translate',
14
+ button: { title: this.data.button, kind: 3 },
15
+ collapseId: 'translate-collapse',
16
+ languages: this._formatLanguages(this.data.languages)
17
+ };
18
+ }
19
+
20
+ _formatLanguages (languages) {
21
+ return languages.map(lang => this._formatLanguage(lang));
22
+ }
23
+
24
+ _formatLanguage (lang) {
25
+ return {
26
+ ...lang,
27
+ href: lang.url
28
+ };
29
+ }
30
+ }
31
+
32
+ export { Translate };
@@ -0,0 +1,21 @@
1
+ import { Component } from '../component.js';
2
+ import { EJS_PKG } from '../ejs-pkg.js';
3
+ class Version extends Component {
4
+ constructor (data) {
5
+ super(data, 'version', EJS_PKG.ROLLER);
6
+ }
7
+ get ejsPath () {
8
+ return 'src/component/ejs/version/version.ejs';
9
+ }
10
+
11
+ async format () {
12
+ return {
13
+ id: 'version',
14
+ button: { title: this.data.button, kind: 3 },
15
+ collapseId: 'version-collapse',
16
+ versions: this.data.versions
17
+ };
18
+ }
19
+ }
20
+
21
+ export { Version };
@@ -0,0 +1,46 @@
1
+ <%#
2
+ # paramètres header version
3
+
4
+ * version (object, optional) : Paramètres du sélecteur de langue
5
+ ** version.id (string) : id de l'élément
6
+ ** version.button (object, optional) : Paramètres du bouton du sélecteur de langue (ex: {kind:3} pour un btn tertiary)
7
+ ** version.collapseId (string, required) : Id du menu à controler
8
+ ** version.versions (array, required) : Tableau d'objets langues
9
+ *** version.versions[].name (string, required) : Nom de la langue dans son alphabet
10
+ *** version.versions[].locale (string, required) : Code de la langue en 2 caratères
11
+ *** version.versions[].active (boolean, required) : La langue qui apparait dans le bouton et en style active dans la liste (1 seule langue active)
12
+ %>
13
+ <%
14
+ const version = locals.version || {};
15
+ const attributes = version.attributes || {};
16
+ attributes.id = version.id || uniqueId('version');
17
+ const collapseId = version.collapseId || uniqueId('version');
18
+ %>
19
+
20
+ <% eval(include(`${dsfrPkg}src/dsfr/core/index.ejs`)); %>
21
+
22
+ <nav role="navigation" class="dsfr-doc-version <%= prefix %>-nav" <%- includeAttrs(attributes) %>>
23
+ <div class="<%= prefix %>-nav__item">
24
+ <%
25
+ const versionBtn = version.button || {};
26
+ const activeVersion = version.versions.find(version => version.active === true);
27
+ versionBtn.label = activeVersion?.label ?? activeVersion?.text;
28
+ const minBtnClasses = [`dsfr-doc-version__btn`];
29
+ const minBtnAttrs = {
30
+ 'aria-controls': collapseId,
31
+ 'aria-expanded': false,
32
+ title: versionBtn.title
33
+ };
34
+ versionBtn.classes = versionBtn.classes !== undefined ? versionBtn.classes.concat(minBtnClasses) : minBtnClasses;
35
+ versionBtn.attributes = versionBtn.attributes !== undefined ? {...minBtnAttrs, ...versionBtn.attributes} : minBtnAttrs;
36
+
37
+ %>
38
+
39
+ <%- include(`${dsfrPkg}src/dsfr/component/button/template/ejs/button`, { button:versionBtn }); %>
40
+
41
+ <div class="<%= prefix %>-collapse dsfr-doc-version__menu <%= prefix %>-menu" id="<%= version.collapseId %>">
42
+
43
+ <%- include('versions.ejs', {versions: version.versions}) %>
44
+ </div>
45
+ </div>
46
+ </nav>
@@ -0,0 +1,31 @@
1
+ <%#
2
+ # paramètres versionSelect Versions
3
+
4
+ * versions (array, required) : Tableau d'objets versions
5
+ ** versions[].id (string) : id de l'élément
6
+ ** versions[].name (string, required) : Nom de la version
7
+
8
+ ** versions[].url (string) : url de la version
9
+ ** versions[].active (boolean, required) : La version qui apparait dans le bouton et en style active dans la liste (1 seule version active)
10
+ ** versions[].badge (string) : complément au nom de version
11
+ %>
12
+ <%
13
+ const versions = locals.versions || {};
14
+ %>
15
+
16
+ <ul class="<%= prefix %>-menu__list">
17
+ <%
18
+ for (let i = 0; i < versions.length; i++) {
19
+ const version = versions[i];
20
+ const attrs = {
21
+ href: version.url,
22
+ id: version.id || uniqueId('version')
23
+ };
24
+ if (version.active) attrs['aria-current'] = true;
25
+ const badge = version.badge !== undefined ? `&nbsp;<span class="${prefix}-badge ${prefix}-badge--new ${prefix}-badge--sm" >${version.badge}</span>` : '';
26
+ %>
27
+ <li>
28
+ <a class="dsfr-doc-version__version <%= prefix %>-nav__link" <%- includeAttrs(attrs); %> ><%= version.text %><%- badge %></a>
29
+ </li>
30
+ <% } %>
31
+ </ul>
@@ -0,0 +1,6 @@
1
+ import { getPackagePath } from '@gouvfr/dsfr-forge';
2
+
3
+ export const EJS_PKG = {
4
+ DSFR: getPackagePath('@gouvfr/dsfr-publisher'),
5
+ ROLLER: getPackagePath('@gouvfr/dsfr-roller')
6
+ }
@@ -0,0 +1,19 @@
1
+ import ejs from 'ejs';
2
+ import { EJS_PKG } from './ejs-pkg.js';
3
+
4
+ let count = 0;
5
+
6
+ const uniqueId = (module) => {
7
+ count++;
8
+ return `${module}-${count}`;
9
+ };
10
+
11
+ const DATA = {
12
+ uniqueId: uniqueId,
13
+ dsfrPkg: EJS_PKG.DSFR,
14
+ relativeRoot: '/'
15
+ };
16
+
17
+ const render = async (template, data, pkg = EJS_PKG.DSFR) => await ejs.render(`<%- include('${pkg}${template}') %>`, {...DATA, ...data});
18
+
19
+ export default render;
@@ -0,0 +1,7 @@
1
+ import { getPackagePath } from '@gouvfr/dsfr-forge';
2
+
3
+ export const ROLLER_MODULE = getPackagePath('@gouvfr/dsfr-roller');
4
+
5
+ export const DOMAIN = 'https://www.systeme-de-design.gouv.fr';
6
+
7
+ export const BANNER = '/*! DSFR | SPDX-License-Identifier: MIT */';
@@ -0,0 +1,16 @@
1
+ import { log } from '@gouvfr/dsfr-forge';
2
+ import * as prettier from 'prettier';
3
+ import htmlParser from 'prettier/parser-html';
4
+
5
+ export const formatHtml = async (html, src = 'unknown') => {
6
+ try {
7
+ const pretty = await prettier.format(html, { parser: 'html', plugins: [htmlParser], tabWidth: 2, });
8
+ return pretty;
9
+ }
10
+ catch (error) {
11
+ log.error(`Error while formatting HTML @ ${src}`);
12
+ log.error(error);
13
+ }
14
+
15
+ return html;
16
+ }
@@ -0,0 +1,8 @@
1
+ export const formatLink = (link) => {
2
+ if (!link) return undefined;
3
+ const url = link.url ?? link.href;
4
+ if (/^(https:|http:|www\.)\S*$/.test(url)) link.blank = true;
5
+ link.href = url;
6
+ link.label = link.label ?? link.text;
7
+ return link;
8
+ };
@@ -0,0 +1,10 @@
1
+ import { Renderable } from './renderable.js';
2
+ import { formatHtml } from './format-html.js';
3
+
4
+ class HtmlRenderable extends Renderable {
5
+ async format (html) {
6
+ return formatHtml(html, this._data.src);
7
+ }
8
+ }
9
+
10
+ export { HtmlRenderable };
@@ -0,0 +1,20 @@
1
+ class Renderable {
2
+ constructor (data) {
3
+ data = this.structure(data);
4
+ this._data = data;
5
+ }
6
+
7
+ structure (data) {
8
+ return data;
9
+ }
10
+
11
+ get data () {
12
+ return this._data;
13
+ }
14
+
15
+ async render () {
16
+ return '';
17
+ }
18
+ }
19
+
20
+ export { Renderable };
@@ -0,0 +1,47 @@
1
+ import { ROLLER_MODULE, BANNER } from '../constants.js';
2
+ import { copyDir, getPackagePath, log } from '@gouvfr/dsfr-forge';
3
+ import { ScriptCompiler, StyleCompiler } from '@gouvfr/dsfr-alchemist'
4
+ import path from 'path'
5
+ import fs from 'fs'
6
+
7
+ class Bundler {
8
+ constructor (dest) {
9
+ this._dest = dest;
10
+ }
11
+
12
+ async copy () {
13
+ await copyDir(`${ROLLER_MODULE}/static`, `${this._dest}/static`);
14
+ }
15
+
16
+ async compile () {
17
+ await this._compileScripts();
18
+ await this._compileStyles();
19
+ }
20
+
21
+ async _compileScripts () {
22
+ const scriptCompiler = new ScriptCompiler();
23
+ const entries = fs.readdirSync(`${ROLLER_MODULE}/src/script`, { withFileTypes: true });
24
+ for (const entry of entries) {
25
+ if (!entry.isDirectory()) continue;
26
+ const index = `${ROLLER_MODULE}/src/script/${entry.name}/index.js`;
27
+ if (!fs.existsSync(index)) continue;
28
+ await scriptCompiler.compile(index, `${this._dest}/lib`, `dsfr-doc-${entry.name}`, {
29
+ minify: true, sourceMap: true, banner: BANNER
30
+ });
31
+ }
32
+ }
33
+
34
+ async _compileStyles () {
35
+ const modulesPath = path.resolve(getPackagePath('@gouvfr/dsfr-publisher'), '../../') + '/';
36
+ const styleCompiler = new StyleCompiler();
37
+ const entries = fs.readdirSync(`${ROLLER_MODULE}/src/style`, { withFileTypes: true });
38
+ for (const entry of entries) {
39
+ if (!entry.isDirectory()) continue;
40
+ const index = `${ROLLER_MODULE}/src/style/${entry.name}/index.scss`;
41
+ if (!fs.existsSync(index)) continue;
42
+ await styleCompiler.compile(index, `${this._dest}/lib`, `dsfr-doc-${entry.name}`, { minify: true, sourceMap: true, banner: BANNER, loadPaths: [modulesPath] });
43
+ }
44
+ }
45
+ }
46
+
47
+ export { Bundler };
@@ -0,0 +1,23 @@
1
+ import { Sitemap } from './sitemap.js';
2
+ import { createFile } from '@gouvfr/dsfr-forge';
3
+ import { DOMAIN } from '../../constants.js';
4
+
5
+ class Indexer {
6
+ constructor (urlSet, dest) {
7
+ this._urlSet = urlSet;
8
+ this._dest = dest;
9
+ }
10
+
11
+ async write () {
12
+ const sitemap = new Sitemap(this._urlSet);
13
+ await sitemap.generate();
14
+
15
+ createFile( `${this._dest}/sitemap.txt`, sitemap.text);
16
+ createFile( `${this._dest}/sitemap.xml`, sitemap.xml);
17
+
18
+ const robots = `Sitemap: ${DOMAIN}/sitemap.xml`;
19
+ createFile( `${this._dest}/robots.txt`, robots);
20
+ }
21
+ }
22
+
23
+ export { Indexer };
@@ -0,0 +1,44 @@
1
+ import { DOMAIN } from '../../constants.js';
2
+ import { formatHtml } from '../../core/format-html.js';
3
+
4
+ class Sitemap {
5
+ constructor (urlSet) {
6
+ this._urlSet = urlSet;
7
+ }
8
+
9
+ async generate () {
10
+ let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">\n';
11
+ let text = '';
12
+
13
+ for (const url of this._urlSet) {
14
+ xml += '<url>\n';
15
+ if (url.hasOwnProperty('loc')) {
16
+ xml += `<loc>${DOMAIN}${url.loc}</loc>\n`;
17
+
18
+
19
+ if (Array.isArray(url.alts)) {
20
+ xml += url.alts.map(alt => `<xhtml:link rel="alternate" hreflang="${alt.lang}" href="${DOMAIN}${alt.url}"/>\n`).join('');
21
+ text += url.alts.map(alt => `${DOMAIN}${alt.url}\n`).join('\n');
22
+ }
23
+ else {
24
+ text += `${DOMAIN}${url.loc}\n`;
25
+ }
26
+ }
27
+ xml += '</url>\n';
28
+ }
29
+ xml += '</urlset>';
30
+
31
+ this._xml = await formatHtml(xml, 'sitemap');
32
+ this._text = text;
33
+ }
34
+
35
+ get text () {
36
+ return this._text;
37
+ }
38
+
39
+ get xml () {
40
+ return this._xml;
41
+ }
42
+ }
43
+
44
+ export { Sitemap };
@@ -0,0 +1,4 @@
1
+ export const RedirectionType = {
2
+ META: 'meta',
3
+ SCRIPT: 'script'
4
+ };
@@ -0,0 +1,77 @@
1
+ import { HtmlRenderable } from '../../core/html-renderable.js';
2
+ import { RedirectionType } from './redirection-type.js'
3
+
4
+ class Redirection extends HtmlRenderable {
5
+ constructor (data) {
6
+ super(data);
7
+ this._dest = data.dest;
8
+ }
9
+
10
+ get dest () {
11
+ return this._dest;
12
+ }
13
+
14
+ get meta () {
15
+ return `
16
+ <meta http-equiv="refresh" content="0; url=${this.data.url}">
17
+ `;
18
+ }
19
+
20
+ get script () {
21
+ return `
22
+ <script>
23
+ const locales = ${JSON.stringify(this.data.locales)};
24
+ const urls = new Map(${JSON.stringify(Object.entries(this.data.urls))});
25
+ const language = navigator.language;
26
+ const code = language.split('-')[0];
27
+
28
+ switch (true) {
29
+ case locales.includes(language):
30
+ window.location.href = urls.get(language);
31
+ break;
32
+
33
+ case locales.includes(code):
34
+ window.location.href = urls.get(code);
35
+ break;
36
+
37
+ case locales.some(locale => locale.startsWith(code)):
38
+ const locale = locales.find(locale => locale.startsWith(code));
39
+ window.location.href = urls.get(locale);
40
+ break;
41
+
42
+ default:
43
+ window.location.href = '${this.data.url}';
44
+ break;
45
+ }
46
+ </script>
47
+ `;
48
+ }
49
+
50
+ get redirection () {
51
+ switch (this.data.type) {
52
+ case RedirectionType.META:
53
+ return this.meta;
54
+ case RedirectionType.SCRIPT:
55
+ return this.script;
56
+ default:
57
+ return '';
58
+ }
59
+ }
60
+
61
+ async render () {
62
+ return this.format(`
63
+ <html lang="${this.data.code}">
64
+ <head>
65
+ <meta charset="UTF-8">
66
+ <title>${this.data.title}</title>
67
+ ${this.redirection}
68
+ </head>
69
+ <body>
70
+ <p>${this.data.text}</p>
71
+ </body>
72
+ </html>
73
+ `);
74
+ }
75
+ }
76
+
77
+ export { Redirection };
@@ -0,0 +1,7 @@
1
+ import { Node } from '../node.js';
2
+
3
+ class HtmlContainerNode extends Node {}
4
+
5
+ HtmlContainerNode.TYPE = 'htmlContainer';
6
+
7
+ export { HtmlContainerNode };
@@ -0,0 +1,59 @@
1
+ import { Node } from '../../node.js'
2
+ import { log } from '@gouvfr/dsfr-forge';
3
+
4
+ class AccordionContainerDirective extends Node {
5
+ structure (data) {
6
+ if (!data.attributes.id) {
7
+ log.warn('AccordionContainerDirective: missing "accordion id"');
8
+ return data;
9
+ }
10
+
11
+ const accordionId = data.attributes.id;
12
+ const titleChildren = data.children.filter(child => child?.data?.directiveLabel)?.[0]?.children;
13
+ const contentChildren = data.children.filter(child => !child?.data?.directiveLabel);
14
+ const titleType = titleChildren[0].value.startsWith('#') ? 'heading' : 'paragraph';
15
+ const titleDepth = /^(#+)/.exec(titleChildren[0].value)?.[1]?.length;
16
+ if (titleType === 'heading') {
17
+ titleChildren[0].value = titleChildren[0].value.replace(/^(#+)\s*/, '');
18
+ }
19
+
20
+ return super.structure({
21
+ type: 'htmlContainer',
22
+ tagName: 'div',
23
+ classes: ['fr-accordion'],
24
+ children: [
25
+ {
26
+ type: titleType,
27
+ depth: titleDepth,
28
+ classes: ['fr-accordion__title'],
29
+ children: [
30
+ {
31
+ type: 'htmlContainer',
32
+ tagName: 'button',
33
+ classes: ['fr-accordion__btn'],
34
+ attributes: {
35
+ type: 'button',
36
+ 'aria-expanded': data.attributes['aria-expanded'] || false,
37
+ 'aria-controls': accordionId
38
+ },
39
+ children: titleChildren
40
+ }
41
+ ]
42
+ },
43
+ {
44
+ type: 'htmlContainer',
45
+ tagName: 'div',
46
+ attributes: {
47
+ id: accordionId
48
+ },
49
+ classes: ['fr-collapse'],
50
+ children: contentChildren
51
+ }
52
+ ]
53
+ });
54
+ }
55
+ }
56
+
57
+ AccordionContainerDirective.NAME = 'fr-accordion';
58
+
59
+ export { AccordionContainerDirective };
@@ -0,0 +1,12 @@
1
+ import { Node } from '../../node.js'
2
+
3
+ class AccordionsGroupContainerDirective extends Node {
4
+ constructor (data) {
5
+ super(data, 'div');
6
+ this.attributes.addClass('fr-accordions-group');
7
+ }
8
+ }
9
+
10
+ AccordionsGroupContainerDirective.NAME = 'fr-accordions-group';
11
+
12
+ export { AccordionsGroupContainerDirective };
@@ -0,0 +1,61 @@
1
+ import { Node } from '../../node.js'
2
+ import { log } from '@gouvfr/dsfr-forge';
3
+
4
+ class AnatomyContainerDirective extends Node {
5
+ structure (data) {
6
+ const image = Node.getImageChild(data);
7
+ const col = data.attributes?.col ?? 12;
8
+
9
+ if (!image) {
10
+ log.warn('GuidelineContainerDirective: missing image');
11
+ return data;
12
+ }
13
+
14
+ const contentChildren = data.children.filter(child => !Node.getImageChild(child));
15
+
16
+ return super.structure({
17
+ type: 'htmlContainer',
18
+ tagName: 'div',
19
+ classes: ['fr-grid-row', 'fr-grid-row--gutters'],
20
+ children: [
21
+ {
22
+ type: 'htmlContainer',
23
+ tagName: 'div',
24
+ classes: ['fr-col-12', `fr-col-sm-${col}`],
25
+ children: [
26
+ {
27
+ type: 'htmlContainer',
28
+ tagName: 'div',
29
+ classes: ['dsfr-doc-anatomy'],
30
+ children: [
31
+ {
32
+ type: 'htmlContainer',
33
+ tagName: 'div',
34
+ classes: ['dsfr-doc-anatomy__image'],
35
+ children: [
36
+ {
37
+ ...image,
38
+ classes: ['fr-responsive-img']
39
+ }
40
+ ]
41
+ },
42
+ {
43
+ type: 'htmlContainer',
44
+ tagName: 'ol',
45
+ classes: ['dsfr-doc-anatomy__content'],
46
+ children: contentChildren
47
+ }
48
+ ]
49
+ }
50
+ ]
51
+ }
52
+ ]
53
+ });
54
+
55
+ }
56
+
57
+ }
58
+
59
+ AnatomyContainerDirective.NAME = 'dsfr-doc-anatomy';
60
+
61
+ export { AnatomyContainerDirective };
@@ -0,0 +1,37 @@
1
+ import { Node } from '../../node.js';
2
+ import { Button } from '../../../component/components/button.js';
3
+
4
+ class ButtonLeafDirective extends Node {
5
+ constructor (data) {
6
+ super(data);
7
+ this.button = new Button(this.data.attributes);
8
+ }
9
+
10
+ structure (data) {
11
+ if (!data.children.some(child => child.type === 'link')) {
12
+ return super.structure(data);
13
+ }
14
+
15
+ const link = data.children.find(child => child.type === 'link');
16
+ const children = data.children.slice();
17
+ children.splice(data.children.indexOf(link), 1, ...link.children);
18
+
19
+ return super.structure({
20
+ ...data,
21
+ attributes: {
22
+ ...data.attributes,
23
+ url: link.url
24
+ },
25
+ children: children
26
+ });
27
+ }
28
+
29
+ async render () {
30
+ const data = { label: await this.renderChildren() };
31
+ return this.button.render(data);
32
+ }
33
+ }
34
+
35
+ ButtonLeafDirective.NAME = 'fr-button';
36
+
37
+ export { ButtonLeafDirective };