From 67c2aed6681853928e1d124eb15f40f594fa9d61 Mon Sep 17 00:00:00 2001 From: Keryan SANIE Date: Thu, 1 Jun 2023 17:42:48 +0200 Subject: [PATCH 01/32] =?UTF-8?q?=F0=9F=9A=9A=20refactor(download):=20s?= =?UTF-8?q?=C3=A9paration=20du=20download=20en=20carte=20et=20lien=20[DS-2?= =?UTF-8?q?972][DS-3244]=20(#487)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pour mutualiser les comportements de la carte et du lien au composant download, celui-ci doit devenir une variante de ces composants et non pas l'inverse. Retrait du composant : téléchargement de fichier - Download -> déprécié Ajout de la variante de carte : fr-card--download Ajout de la variante de lien : fr-link--download Le lien de téléchargement : ```html

Télécharger le document lorem ipsum sit dolores amet JPG – 61,88 ko

``` DEVIENT : ```html Télécharger le document lorem ipsum sit dolores amet JPG – 61,88 ko ``` et la carte de téléchargement : ```html ``` DEVIENT : ```html ``` BREAKING CHANGE : Remplacer le composant fr-download par la variante de link fr-link--download et remplacer le composant fr-download--card par une carte fr-card--download --- src/analytics/.package.yml | 1 - .../example/component/card/index.ejs | 5 ++ .../example/component/download/index.ejs | 2 +- src/component/card/.package.yml | 2 + src/component/{download => card}/api.js | 0 src/component/card/example/download/index.ejs | 43 ++++++++++++ .../example/download/sample/card-download.ejs | 17 +++++ .../download/sample/sample-content.ejs | 9 +++ .../download/sample/sample-horizontal.ejs | 4 ++ .../example/download/sample/sample-img.ejs | 9 +++ .../example/download/sample/sample-no-img.ejs | 5 ++ .../example/download/sample/sample-sizes.ejs | 9 +++ src/component/card/example/index.ejs | 6 +- .../card/example/sample/card-default.ejs | 20 ++++-- .../card/example/sample/sample-disabled.ejs | 3 + .../card/example/sample/sample-icon.ejs | 4 +- src/component/card/i18n/fr.yml | 7 ++ src/component/card/index.js | 10 +++ src/component/card/main.js | 6 ++ .../card/script/card/card-download.js | 18 +++++ .../card/script/card/card-selector.js | 6 ++ src/component/card/style/_module.scss | 1 + src/component/card/style/_scheme.scss | 11 ++- src/component/card/style/module/_default.scss | 22 ++++-- .../card/style/module/_download.scss | 62 ++++++++++++++++ src/component/card/style/module/_lg.scss | 17 ++--- src/component/card/style/module/_sm.scss | 17 ++--- src/component/card/template/ejs/card.ejs | 19 +++-- src/component/card/template/ejs/content.ejs | 15 +++- src/component/download/.package.yml | 4 +- .../download/deprecated/example/index.ejs | 45 ++++++++++++ .../{ => deprecated}/example/layout.ejs | 0 .../example/sample/download-card-grid.ejs | 0 .../example/sample/download-card.ejs | 0 .../example/sample/download-default.ejs | 0 .../example/sample/download-group.ejs | 0 .../example/sample/sample-assess-js.ejs | 0 .../example/sample/sample-card-group.ejs | 0 .../example/sample/sample-card.ejs | 0 .../example/sample/sample-default.ejs | 0 .../example/sample/sample-group-link.ejs | 0 .../example/sample/sample-lang.ejs | 0 .../{ => deprecated}/style/_module.scss | 0 .../{ => deprecated}/style/_scheme.scss | 2 +- .../{ => deprecated}/style/_setting.scss | 0 .../{ => deprecated}/style/_tool.scss | 0 .../style/module/_download.scss | 0 .../{ => deprecated}/style/module/_group.scss | 0 .../style/module/_variants.scss | 0 .../template/ejs/download.ejs | 2 +- .../template/ejs/downloads-group.ejs | 2 +- .../download/example/deprecated/index.ejs | 3 + src/component/download/example/index.ejs | 45 ------------ src/component/download/i18n/fr.yml | 6 ++ src/component/download/index.js | 11 --- src/component/download/index.scss | 4 +- src/component/download/main.js | 5 -- src/component/download/main.scss | 4 +- .../script/download/download-selector.js | 6 -- .../link/example/back-to-top/index.ejs | 5 ++ .../sample/link-back-to-top.ejs | 2 +- src/component/link/example/download/index.ejs | 13 ++++ .../link/example/download/layout-english.ejs | 0 .../download/sample/download-default.ejs | 14 ++++ .../download/sample/download-group.ejs | 16 +++++ src/component/link/example/index.ejs | 4 +- src/component/link/i18n/fr.yml | 7 ++ src/component/link/style/_module.scss | 1 + src/component/link/style/_scheme.scss | 14 ++++ .../link/style/module/_download.scss | 45 ++++++++++++ src/component/link/style/module/_group.scss | 29 ++++++-- src/component/link/template/ejs/link.ejs | 22 +++++- .../link/template/ejs/links-group.ejs | 2 + src/component/main.js | 2 +- src/component/tile/style/_scheme.scss | 5 +- src/core/index.js | 8 +++ src/core/main.js | 2 + src/core/script/assess/assess-detail.js | 19 +++++ src/core/script/assess/assess-emission.js | 8 +++ .../script/assess}/assess-file.js | 66 ++++++++++++------ src/core/script/assess/assess-selector.js | 6 ++ tool/example/img/placeholder.32x9.png | Bin 0 -> 4529 bytes tool/example/img/placeholder.3x4.png | Bin 0 -> 1161 bytes tool/example/img/placeholder.4x3.png | Bin 0 -> 950 bytes 84 files changed, 623 insertions(+), 156 deletions(-) rename src/component/{download => card}/api.js (100%) create mode 100644 src/component/card/example/download/index.ejs create mode 100755 src/component/card/example/download/sample/card-download.ejs create mode 100644 src/component/card/example/download/sample/sample-content.ejs create mode 100644 src/component/card/example/download/sample/sample-horizontal.ejs create mode 100644 src/component/card/example/download/sample/sample-img.ejs create mode 100644 src/component/card/example/download/sample/sample-no-img.ejs create mode 100644 src/component/card/example/download/sample/sample-sizes.ejs create mode 100755 src/component/card/example/sample/sample-disabled.ejs create mode 100644 src/component/card/i18n/fr.yml create mode 100644 src/component/card/index.js create mode 100644 src/component/card/main.js create mode 100644 src/component/card/script/card/card-download.js create mode 100644 src/component/card/script/card/card-selector.js create mode 100644 src/component/card/style/module/_download.scss create mode 100755 src/component/download/deprecated/example/index.ejs rename src/component/download/{ => deprecated}/example/layout.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/download-card-grid.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/download-card.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/download-default.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/download-group.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/sample-assess-js.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/sample-card-group.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/sample-card.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/sample-default.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/sample-group-link.ejs (100%) rename src/component/download/{ => deprecated}/example/sample/sample-lang.ejs (100%) rename src/component/download/{ => deprecated}/style/_module.scss (100%) rename src/component/download/{ => deprecated}/style/_scheme.scss (92%) rename src/component/download/{ => deprecated}/style/_setting.scss (100%) rename src/component/download/{ => deprecated}/style/_tool.scss (100%) rename src/component/download/{ => deprecated}/style/module/_download.scss (100%) rename src/component/download/{ => deprecated}/style/module/_group.scss (100%) rename src/component/download/{ => deprecated}/style/module/_variants.scss (100%) rename src/component/download/{ => deprecated}/template/ejs/download.ejs (98%) rename src/component/download/{ => deprecated}/template/ejs/downloads-group.ejs (96%) create mode 100644 src/component/download/example/deprecated/index.ejs mode change 100755 => 100644 src/component/download/example/index.ejs create mode 100644 src/component/download/i18n/fr.yml delete mode 100644 src/component/download/index.js delete mode 100644 src/component/download/main.js delete mode 100644 src/component/download/script/download/download-selector.js create mode 100644 src/component/link/example/back-to-top/index.ejs rename src/component/link/example/{ => back-to-top}/sample/link-back-to-top.ejs (71%) create mode 100755 src/component/link/example/download/index.ejs create mode 100644 src/component/link/example/download/layout-english.ejs create mode 100755 src/component/link/example/download/sample/download-default.ejs create mode 100755 src/component/link/example/download/sample/download-group.ejs create mode 100644 src/component/link/i18n/fr.yml create mode 100644 src/component/link/style/module/_download.scss create mode 100644 src/core/script/assess/assess-detail.js create mode 100644 src/core/script/assess/assess-emission.js rename src/{component/download/script/download => core/script/assess}/assess-file.js (56%) create mode 100644 src/core/script/assess/assess-selector.js create mode 100644 tool/example/img/placeholder.32x9.png create mode 100644 tool/example/img/placeholder.3x4.png create mode 100644 tool/example/img/placeholder.4x3.png diff --git a/src/analytics/.package.yml b/src/analytics/.package.yml index 43bade2af..6d5220004 100644 --- a/src/analytics/.package.yml +++ b/src/analytics/.package.yml @@ -19,7 +19,6 @@ script: - display - table - tag - - download example: style: - core diff --git a/src/analytics/example/component/card/index.ejs b/src/analytics/example/component/card/index.ejs index 99721d25e..d2e6f48aa 100755 --- a/src/analytics/example/component/card/index.ejs +++ b/src/analytics/example/component/card/index.ejs @@ -6,4 +6,9 @@ <%- sample('Carte', '../../../../component/card/example/sample/card-default', { card : { title: 'Intitulé de la carte', img: true, href: '../' }}); %> +
+
+ <%- sample('Carte de téléchargement', '../../../../component/card/example/download/sample/card-download', { card: {img: false} }); %> +
+
diff --git a/src/analytics/example/component/download/index.ejs b/src/analytics/example/component/download/index.ejs index 719e0fa62..5220d345c 100644 --- a/src/analytics/example/component/download/index.ejs +++ b/src/analytics/example/component/download/index.ejs @@ -1,5 +1,5 @@ <% const sample = getSample(include); %>
- <%- sample('Téléchargement de fichier', '../../../../component/download/example/sample/download-default', { download: { id: 'download' }}); %> + <%- sample('Téléchargement de fichier', '../../../../component/download/deprecated/example/sample/download-default', { download: { id: 'download' }}); %>
diff --git a/src/component/card/.package.yml b/src/component/card/.package.yml index b17918f52..9d40d8892 100644 --- a/src/component/card/.package.yml +++ b/src/component/card/.package.yml @@ -8,3 +8,5 @@ style: - button - badge - tag +script: + - core diff --git a/src/component/download/api.js b/src/component/card/api.js similarity index 100% rename from src/component/download/api.js rename to src/component/card/api.js diff --git a/src/component/card/example/download/index.ejs b/src/component/card/example/download/index.ejs new file mode 100644 index 000000000..73a857997 --- /dev/null +++ b/src/component/card/example/download/index.ejs @@ -0,0 +1,43 @@ + +<% const sample = getSample(include); %> + +<% + const elements = [ + { + title: 'Tailles', + path: 'sample-sizes' + }, + { + title: 'Sans image', + path: 'sample-no-img' + }, + { + title: 'Image et ratio', + path: 'sample-img' + }, + { + title: 'Contenu', + path: 'sample-content' + }, + { + title: 'Carte horizontale', + path: 'sample-horizontal' + }, + ]; + + const accordions = []; + + for (let element of elements) { + accordions.push({ + label: element.title, + id: uniqueId('card-download'), + content: include(`./sample/${element.path}`) + }) + } + + const data = { + accordions: accordions + } + %> + +<%- include('../../../accordion/template/ejs/accordions-group', {accordionsGroup: data }); %> diff --git a/src/component/card/example/download/sample/card-download.ejs b/src/component/card/example/download/sample/card-download.ejs new file mode 100755 index 000000000..e7cdbbaa1 --- /dev/null +++ b/src/component/card/example/download/sample/card-download.ejs @@ -0,0 +1,17 @@ +<% + +const card = locals.card || {} +const data = { + img: imgData('img/placeholder.3x4.png', 'unknown'), + title: "Télécharger le/la [Typologie de document] « [Nom du document] »", + href: '/example/img/placeholder.3x4.png', + download: true, + content: { + description: "Texte de description (facultatif)" + }, + ...card +} %> + +<%- include('../../sample/card-default', {card: data}) %> + + diff --git a/src/component/card/example/download/sample/sample-content.ejs b/src/component/card/example/download/sample/sample-content.ejs new file mode 100644 index 000000000..abe6689e4 --- /dev/null +++ b/src/component/card/example/download/sample/sample-content.ejs @@ -0,0 +1,9 @@ +<% const sample = getSample(include); %> + +<%- sample('Carte de téléchargement, cas maximum', './card-download', { card : { content: { details: ['icon'], badges: true } } }, true, '../../sample/card-layout', {col: {sm: 6}}); %> + +<%- sample('Carte de téléchargement, cas minimum', './card-download', { card : { img: false, content: { description: false } } }, true, '../../sample/card-layout', {col: {sm: 6}}); %> + +<%- sample('Carte de téléchargement, avec tags', './card-download', { card : { content: { tags: true} }}, true, '../../sample/card-layout', {col: {sm: 6}}); %> + +<%- sample('Carte de téléchargement, avec remplissage automatique des détails', './card-download', { card : { content: { assess: true} }}, true, '../../sample/card-layout', {col: {sm: 6}, desc: 'L\'attribut data-fr-assess-file permet de remplir automatiquement le detail depuis les informations du fichier (extension, poids, langue)'}); %> diff --git a/src/component/card/example/download/sample/sample-horizontal.ejs b/src/component/card/example/download/sample/sample-horizontal.ejs new file mode 100644 index 000000000..bb06ba2f0 --- /dev/null +++ b/src/component/card/example/download/sample/sample-horizontal.ejs @@ -0,0 +1,4 @@ +<% const sample = getSample(include); %> + +<%- sample('Carte de téléchargement sm horizontale', './card-download', { card : { size: 'sm', horizontal: true }}, true, '../../sample/card-layout', {col: {sm:6}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> +<%- sample('Carte de téléchargement md horizontale', './card-download', { card : { size: 'md', horizontal: true }}, true, '../../sample/card-layout', {col: {sm:6}, desc: 'dans une grille sur 6 à 8 colonnes en version desktop'}); %> diff --git a/src/component/card/example/download/sample/sample-img.ejs b/src/component/card/example/download/sample/sample-img.ejs new file mode 100644 index 000000000..62c265be2 --- /dev/null +++ b/src/component/card/example/download/sample/sample-img.ejs @@ -0,0 +1,9 @@ +<% const sample = getSample(include); %> + +<%- sample('Carte de téléchargement, image 3x4', './card-download', {}, true, '../../sample/card-layout', {col: {sm:6, md: 4}}); %> +<%- sample('Carte de téléchargement, image 4x3', './card-download', { card : { img: imgData('img/placeholder.4x3.png', 'unknown') }}, true, '../../sample/card-layout', {col: {sm:6, md: 4}}); %> +<%- sample('Carte de téléchargement, image 32x9', './card-download', { card : { img: imgData('img/placeholder.32x9.png', 'unknown') }}, true, '../../sample/card-layout', {col: {sm:6, md: 4}}); %> + +<%- sample('Carte de téléchargement horizontale, image 3x4', './card-download', { card : { horizontal: true }}, true, '../../sample/card-layout', {col: {md:6}}); %> +<%- sample('Carte de téléchargement horizontale, image 4x3', './card-download', { card : { horizontal: true, img: imgData('img/placeholder.4x3.png', 'unknown') }}, true, '../../sample/card-layout', {col: {md:6}}); %> +<%- sample('Carte de téléchargement horizontale, image 32x9', './card-download', { card : { horizontal: true, img: imgData('img/placeholder.32x9.png', 'unknown') }}, true, '../../sample/card-layout', {col: {sm:6, md: 4}}); %> diff --git a/src/component/card/example/download/sample/sample-no-img.ejs b/src/component/card/example/download/sample/sample-no-img.ejs new file mode 100644 index 000000000..1aaa3da4d --- /dev/null +++ b/src/component/card/example/download/sample/sample-no-img.ejs @@ -0,0 +1,5 @@ +<% const sample = getSample(include); %> + +<%- sample('Carte de téléchargement, sans image', './card-download', {card: {img: false}}, true, '../../sample/card-layout', {col: {md:6}}); %> + +<%- sample('Carte de téléchargement horizontale, sans image', './card-download', { card : { img: false, horizontal: true }}, true, '../../sample/card-layout', {col: {md:6}}); %> diff --git a/src/component/card/example/download/sample/sample-sizes.ejs b/src/component/card/example/download/sample/sample-sizes.ejs new file mode 100644 index 000000000..089dbfa5e --- /dev/null +++ b/src/component/card/example/download/sample/sample-sizes.ejs @@ -0,0 +1,9 @@ +<% const sample = getSample(include); %> + +<%- sample('Carte de téléchargement sm', './card-download', { card : { size: 'sm' }}, true, '../../sample/card-layout', {col: {sm: 6, md:4}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> +<%- sample('Carte de téléchargement md', './card-download', { card : { size: 'md' }}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 6 à 8 colonnes en version desktop'}); %> +<%- sample('Carte de téléchargement lg', './card-download', { card : { size: 'lg' }}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 8 à 12 colonnes en version desktop'}); %> + +<%- sample('Carte de téléchargement sm horizontal', './card-download', { card : { size: 'sm', horizontal: true}}, true, '../../sample/card-layout', {col: {sm:6}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> +<%- sample('Carte de téléchargement md horizontal', './card-download', { card : { size: 'md', horizontal: true}}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 6 à 8 colonnes en version desktop'}); %> +<%- sample('Carte de téléchargement lg horizontal', './card-download', { card : { size: 'lg', horizontal: true}}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 8 à 12 colonnes en version desktop'}); %> diff --git a/src/component/card/example/index.ejs b/src/component/card/example/index.ejs index 545a8a4de..b58399114 100755 --- a/src/component/card/example/index.ejs +++ b/src/component/card/example/index.ejs @@ -7,7 +7,7 @@ path: 'sample-sizes' }, { - title: 'Lien élargi', + title: 'Lien non élargi', path: 'sample-enlarge' }, { @@ -38,6 +38,10 @@ title: 'Contenu', path: 'sample-content' }, + { + title: 'Desactivé', + path: 'sample-disabled' + }, { title: 'Zone d\'action', path: 'sample-footer' diff --git a/src/component/card/example/sample/card-default.ejs b/src/component/card/example/sample/card-default.ejs index 64e9628e1..c50345758 100755 --- a/src/component/card/example/sample/card-default.ejs +++ b/src/component/card/example/sample/card-default.ejs @@ -1,11 +1,10 @@ <% const card = locals.card || {}; -const href = card.href || '#' +const href = card.href || '#'; const data = { content: { title: card.title || 'Intitulé de la carte (sur lequel se trouve le lien)', - description: card.description || lorem('', 160), - href: href + href: href, }, id: card.id || uniqueId('card'), size: card.size, @@ -49,9 +48,14 @@ if (card.img || card.vid) { } if (card.content) { + if (card.content.assess) data.content.assess = card.content.assess; + if (card.content.disabled) data.content.disabled = card.content.disabled; + if (card.content.blank) data.content.blank = card.content.blank; + + if (card.content.description !== false) data.content.description = card.content.description || lorem('', 160); if (card.content.badges) { - data.content.badgesGroup = { badges: [...Array(2)].map(() => { return { label: 'label badge'}})}; + data.content.badgesGroup = { badges: [...Array(2)].map(() => { return { label: 'label badge', accent: 'purple-glycine'}})}; } if (card.content.tags) { @@ -72,6 +76,12 @@ if (card.content) { } } +if (card.download) { + data.download = true; + if (!data.content.details) data.content.details = []; + data.content.details.push({ label: 'PNG - 1,1 ko', position: 'end'}); +} + if (card.footer) { data.footer = {}; const label = 'Label'; @@ -79,7 +89,7 @@ if (card.footer) { data.footer.buttonsGroup = { buttons: [{label: label, kind: 2}, {label: label, kind: 1}], reverse: true, inline:'lg' } } if (card.footer.links) { - data.footer.linksGroup = { links: [...Array(2)].map(() => { return { label: 'label', href: href, icon: 'arrow-right-line', iconPlace: 'right'}})}; + data.footer.linksGroup = { inline: true, links: [...Array(2)].map(() => { return { label: 'label', inline: true, href:'#', icon: 'arrow-right-line', iconPlace: 'right'}})}; } } diff --git a/src/component/card/example/sample/sample-disabled.ejs b/src/component/card/example/sample/sample-disabled.ejs new file mode 100755 index 000000000..3fadbe833 --- /dev/null +++ b/src/component/card/example/sample/sample-disabled.ejs @@ -0,0 +1,3 @@ +<% const sample = getSample(include); %> + +<%- sample('Carte avec lien désactivé (a sans href)', './card-default', { card : { img: true, content: {disabled:true} }}, true, './card-layout', {col: {md:4}}); %> diff --git a/src/component/card/example/sample/sample-icon.ejs b/src/component/card/example/sample/sample-icon.ejs index e90b9720e..d8caadaa6 100755 --- a/src/component/card/example/sample/sample-icon.ejs +++ b/src/component/card/example/sample/sample-icon.ejs @@ -1,5 +1,5 @@ <% const sample = getSample(include); %> -<%- sample('Carte verticale sans icône', './card-default', { card : { img: true, icon: false }}, true, './card-layout', {col: {md:4}}); %> +<%- sample('Carte sans icône', './card-default', { card : { img: true, icon: false }}, true, './card-layout', {col: {md:4}}); %> -<%- sample('Carte verticale avec icône personnalisée', './card-default', { card : { img: true, icon: 'warning-fill' }}, true, './card-layout', {col: {md:4}}); %> +<%- sample('Carte avec icône lien externe', './card-default', { card : { img: true, content: { blank: true } }}, true, './card-layout', {col: {md:4}}); %> diff --git a/src/component/card/i18n/fr.yml b/src/component/card/i18n/fr.yml new file mode 100644 index 000000000..fb9f85fb1 --- /dev/null +++ b/src/component/card/i18n/fr.yml @@ -0,0 +1,7 @@ +title: Carte +description: La carte donne des aperçus cliquables d’une page de contenu à l’utilisateur. Elle fait généralement partie d'une collection ou liste d’aperçus de contenu similaires. La carte n’est jamais présentée de manière isolée. +doc: https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/carte +subdir: + title: Carte de téléchargement de fichier + description: Ce composant permet aux utilisateurs de télécharger un fichier. + download: Carte de téléchargement \ No newline at end of file diff --git a/src/component/card/index.js b/src/component/card/index.js new file mode 100644 index 000000000..53519fc31 --- /dev/null +++ b/src/component/card/index.js @@ -0,0 +1,10 @@ +import api from './api.js'; +import { CardDownload } from './script/card/card-download.js'; +import { CardSelector } from './script/card/card-selector.js'; + +api.card = { + CardSelector: CardSelector, + CardDownload: CardDownload +}; + +export default api; diff --git a/src/component/card/main.js b/src/component/card/main.js new file mode 100644 index 000000000..0a2cfb018 --- /dev/null +++ b/src/component/card/main.js @@ -0,0 +1,6 @@ +import api from './index.js'; + +api.internals.register(api.card.CardSelector.DOWNLOAD, api.card.CardDownload); +api.internals.register(api.card.CardSelector.DOWNLOAD_DETAIL, api.core.AssessDetail); + +export default api; diff --git a/src/component/card/script/card/card-download.js b/src/component/card/script/card/card-download.js new file mode 100644 index 000000000..11e97d322 --- /dev/null +++ b/src/component/card/script/card/card-download.js @@ -0,0 +1,18 @@ +import api from '../../api.js'; + +class CardDownload extends api.core.Instance { + static get instanceClassName () { + return 'CardDownload'; + } + + init () { + this.addAscent(api.core.AssessEmission.UPDATE, details => { + this.descend(api.core.AssessEmission.UPDATE, details); + }); + this.addAscent(api.core.AssessEmission.ADDED, () => { + this.descend(api.core.AssessEmission.ADDED); + }); + } +} + +export { CardDownload }; diff --git a/src/component/card/script/card/card-selector.js b/src/component/card/script/card/card-selector.js new file mode 100644 index 000000000..b09b2cc1c --- /dev/null +++ b/src/component/card/script/card/card-selector.js @@ -0,0 +1,6 @@ +import api from '../../api.js'; + +export const CardSelector = { + DOWNLOAD: api.internals.ns.selector('card--download'), + DOWNLOAD_DETAIL: `${api.internals.ns.selector('card--download')} ${api.internals.ns.selector('card__end')} ${api.internals.ns.selector('card__detail')}` +}; diff --git a/src/component/card/style/_module.scss b/src/component/card/style/_module.scss index abe96a14f..590958f42 100644 --- a/src/component/card/style/_module.scss +++ b/src/component/card/style/_module.scss @@ -10,3 +10,4 @@ @import 'module/sm'; @import 'module/lg'; @import 'module/horizontal'; +@import 'module/download'; diff --git a/src/component/card/style/_scheme.scss b/src/component/card/style/_scheme.scss index 3f570c2e0..a26cc5dc9 100644 --- a/src/component/card/style/_scheme.scss +++ b/src/component/card/style/_scheme.scss @@ -5,6 +5,7 @@ @use 'module/color'; @use 'module/elevation'; +@use 'module/disabled'; @mixin _card-scheme($legacy: false) { #{ns(card)} { @@ -30,8 +31,10 @@ @include color.transparent-background((legacy:$legacy, hover: true)); } - @include before { - @include color.text(action-high blue-france, (legacy:$legacy)); + &--download:not(#{ns(card--no-background)}) { + #{ns(card__header)} { + @include color.background(alt grey, (legacy:$legacy)); + } } &__detail { @@ -39,7 +42,9 @@ } &__title { - @include color.text(title grey, (legacy:$legacy)); + @include color.text(action-high blue-france, (legacy:$legacy)); + + @include disabled.selector((can-be-link: true), (legacy: $legacy, text: true, background: true)); } } } diff --git a/src/component/card/style/module/_default.scss b/src/component/card/style/module/_default.scss index a5762a124..436c473d1 100644 --- a/src/component/card/style/module/_default.scss +++ b/src/component/card/style/module/_default.scss @@ -6,16 +6,24 @@ #{ns(card)} { @include display-flex(column); @include relative(); - @include icon(arrow-right-line); - &--no-icon, - &:not(#{ns(enlarge-link)}) { - @include before(none); + &__title { + a { + @include icon(arrow-right-line, md, after) { + @include absolute(null, 8v, 8v); + } + } + + a[target=_blank] { + @include icon(external-link-line, md, after); + } } - @include before { - @include absolute(null, 8v, 8v); - @include icon-size(md); + &--no-icon, + &:not(#{ns(enlarge-link)}) { + #{ns(card__title a)} { + @include after(none); + } } @include body() { diff --git a/src/component/card/style/module/_download.scss b/src/component/card/style/module/_download.scss new file mode 100644 index 000000000..c41dca849 --- /dev/null +++ b/src/component/card/style/module/_download.scss @@ -0,0 +1,62 @@ +@use '../../../../../module/media-query'; + +#{ns(card--download)} { + @include media-query.respond-from(md) { + flex-direction: row; + + #{ns(card__header)} { + @include width(40%); + flex: 0 0 40%; + aspect-ratio: auto; + + #{ns(card__img)} { + img { + object-position: 50% 0; + } + } + } + + #{ns(card__img)} { + height: 100%; + + img { + height: 100%; + object-fit: cover; + } + } + } + + #{ns(card__header)} { + aspect-ratio: #{16/9}; + + #{ns(card__img)} { + @include absolute(2v, null, null, 2v, calc(100% - 4v), calc(100% - 4v)); + + img { + @include max-width(100%); + @include max-height(100%); + object-fit: contain; + } + } + } + + &#{ns(enlarge-link)} { + #{ns(card__title a)} { + @include icon(download-line, null, after); + } + + @include hover-media-query { + &:hover { + #{ns(card__header)} { + background-color: var(--hover); + } + } + + &:active { + #{ns(card__header)} { + background-color: var(--active); + } + } + } + } +} diff --git a/src/component/card/style/module/_lg.scss b/src/component/card/style/module/_lg.scss index 0a9070360..7e0cacc2c 100644 --- a/src/component/card/style/module/_lg.scss +++ b/src/component/card/style/module/_lg.scss @@ -4,14 +4,6 @@ //// #{ns(card)} { - &--lg { - @include before { - @include icon-size(lg); - @include right(10v); - @include bottom(10v); - } - } - &--lg &__content { @include nest-tag(md); @include padding(10v); @@ -54,6 +46,15 @@ @include padding-bottom(26v); // 10v (padding card) + 8v (icon) + 2v (padding end) + 6v (marge texte icon) } + &--lg#{ns(enlarge-link)}:not(&--no-icon) &__title { + a { + @include icon-size(lg, after) { + @include right(10v); + @include bottom(10v); + } + } + } + &--lg &__footer { @include padding(2v 10v 10v); } diff --git a/src/component/card/style/module/_sm.scss b/src/component/card/style/module/_sm.scss index 98569967e..bccef8c17 100644 --- a/src/component/card/style/module/_sm.scss +++ b/src/component/card/style/module/_sm.scss @@ -4,14 +4,6 @@ //// #{ns(card)} { - &--sm { - @include before { - @include icon-size(sm); - @include right(6v); - @include bottom(6v); - } - } - &--sm &__header { @include nest-badge(sm); } @@ -55,6 +47,15 @@ @include padding-bottom(14v); // 6v (padding card) + 4v (icon) + 1v (padding end) + 3v (marge texte icon) } + &--sm#{ns(enlarge-link)}:not(&--no-icon) &__title { + a { + @include icon-size(sm, after) { + @include right(6v); + @include bottom(6v); + } + } + } + &--sm &__footer { @include padding(2v 6v 6v); } diff --git a/src/component/card/template/ejs/card.ejs b/src/component/card/template/ejs/card.ejs index a11988000..1f0d764e3 100644 --- a/src/component/card/template/ejs/card.ejs +++ b/src/component/card/template/ejs/card.ejs @@ -16,7 +16,9 @@ * card.icon (string or boolean, optional) : icône illustrative ou suppression de l'icon avec false -* card.variations (array, optional): variations ésthétiques de la carte (valeurs: accent, no-border, no-background, shadow +* card.variations (array, optional): variations ésthétiques de la carte (valeurs: accent, no-border, no-background, shadow) + +* card.download (boolean, optional): Si true, carte de téléchargement * card.classes (array, optional): Classes suplémentaires sur le composant @@ -24,10 +26,11 @@ <% eval(include('../../../../core/index.ejs')); %> <% -let card = locals.card || {}; -let classes = card.classes || []; -let attributes = card.attributes || {}; +const card = locals.card || {}; +const classes = card.classes || []; +const attributes = card.attributes || {}; classes.push(`${prefix}-card`); +const content = card.content || {}; if (card.id) attributes.id = card.id; @@ -58,6 +61,11 @@ if (card.horizontal !== undefined) { } } +if (card.download === true) { + classes.push(`${prefix}-card--download`); + content.downloadable = true; +} + switch (card.icon) { case undefined: break; @@ -88,11 +96,10 @@ if (card.variations) for (const variation of card.variations) switch(variation) break; } -// if (card.accent !== undefined) %>
<%- includeClasses(classes) %>>
- <%- include('content', { content: card.content}) %> + <%- include('content', { content: content}) %> <% if (card.footer !== undefined) { %> <%- include('footer', { footer: card.footer}) %> <% } %> diff --git a/src/component/card/template/ejs/content.ejs b/src/component/card/template/ejs/content.ejs index 9441c0b86..e975ecc4b 100644 --- a/src/component/card/template/ejs/content.ejs +++ b/src/component/card/template/ejs/content.ejs @@ -17,6 +17,8 @@ * content.markup (string, optional) : (défaut : h3) niveau de titre +* content.assess (String, optional): remplissage automatique du poid et type de fichier à telecharger + %> <% let start, end; @@ -25,6 +27,17 @@ const startDetails = content.details ? content.details.filter(detail => !detail. const markup = content.markup || 'h3'; const hasLink = !content.noLink; +const href = content.href || '#'; +const attributes = {} +if (content.assess === true) { + attributes[`data-${prefix}-assess-file`] = ''; +} else if (typeof(content.assess) === 'string') { + attributes[`data-${prefix}-assess-file`] = content.assess; +} +if (content.disabled !== true) attributes.href = href; +if (content.lang) attributes.hreflang = content.lang; +if (content.blank === true) attributes.target = '_blank'; +if (content.downloadable === true) attributes.download = ''; switch (true) { case content.badgesGroup !== undefined : @@ -49,7 +62,7 @@ switch (true) {
<<%= markup %> class="<%= prefix %>-card__title"> - <% if (hasLink) { %><% } %> + <% if (hasLink) { %>><% } %> <%- content.title %> <% if (hasLink) { %><% } %> > diff --git a/src/component/download/.package.yml b/src/component/download/.package.yml index 419c7e58f..d28439675 100644 --- a/src/component/download/.package.yml +++ b/src/component/download/.package.yml @@ -1,9 +1,7 @@ id: download title: Téléchargement de fichier -description: Ce composant permet aux utilisateurs de télécharger un ou plusieurs fichiers. +description: Ce composant est déprécié. La fonctionnalité "téléchargement de fichier" est maintenant disponible directement sur le composant carte et le composant lien. doc: https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/telechargement-de-fichier wrapper: container style: - core -script: - - core diff --git a/src/component/download/deprecated/example/index.ejs b/src/component/download/deprecated/example/index.ejs new file mode 100755 index 000000000..b8156950c --- /dev/null +++ b/src/component/download/deprecated/example/index.ejs @@ -0,0 +1,45 @@ +<% +const sample = getSample(include); +const elements = [ + { + title: 'Lien de téléchargement', + path: 'sample-default' + }, + { + title: 'Groupe de liens', + path: 'sample-group-link' + }, + { + title: 'Carte de téléchargement', + path: 'sample-card' + }, + { + title: 'Groupe de cartes', + path: 'sample-card-group' + }, + { + title: 'Fichier en langue étrangère', + path: 'sample-lang' + }, + { + title: 'Utilitaire js', + path: 'sample-assess-js' + }, +]; + +const accordions = []; +for (let element of elements) { + accordions.push({ + label: element.title, + id: uniqueId('download'), + content: include(`./sample/${element.path}`) + }) +} +const data = { + accordions: accordions +} +%> + +<%- section('Téléchargement de fichier', 'Il existe 2 variantes possible pour ce composant. La forme de lien, et la forme de carte.
L\'intitulé du lien doit commencer par ‘Télécharger’.
Le détail est obligatoire et doit conntenir le type (extension du fichier), le poids, la langue (si différente)). Laisser le détail vide si utilisation de l\'utilitaire js de remplissage automatique', 0); %> + +<%- include('../../../accordion/template/ejs/accordions-group', {accordionsGroup: data }); %> \ No newline at end of file diff --git a/src/component/download/example/layout.ejs b/src/component/download/deprecated/example/layout.ejs similarity index 100% rename from src/component/download/example/layout.ejs rename to src/component/download/deprecated/example/layout.ejs diff --git a/src/component/download/example/sample/download-card-grid.ejs b/src/component/download/deprecated/example/sample/download-card-grid.ejs similarity index 100% rename from src/component/download/example/sample/download-card-grid.ejs rename to src/component/download/deprecated/example/sample/download-card-grid.ejs diff --git a/src/component/download/example/sample/download-card.ejs b/src/component/download/deprecated/example/sample/download-card.ejs similarity index 100% rename from src/component/download/example/sample/download-card.ejs rename to src/component/download/deprecated/example/sample/download-card.ejs diff --git a/src/component/download/example/sample/download-default.ejs b/src/component/download/deprecated/example/sample/download-default.ejs similarity index 100% rename from src/component/download/example/sample/download-default.ejs rename to src/component/download/deprecated/example/sample/download-default.ejs diff --git a/src/component/download/example/sample/download-group.ejs b/src/component/download/deprecated/example/sample/download-group.ejs similarity index 100% rename from src/component/download/example/sample/download-group.ejs rename to src/component/download/deprecated/example/sample/download-group.ejs diff --git a/src/component/download/example/sample/sample-assess-js.ejs b/src/component/download/deprecated/example/sample/sample-assess-js.ejs similarity index 100% rename from src/component/download/example/sample/sample-assess-js.ejs rename to src/component/download/deprecated/example/sample/sample-assess-js.ejs diff --git a/src/component/download/example/sample/sample-card-group.ejs b/src/component/download/deprecated/example/sample/sample-card-group.ejs similarity index 100% rename from src/component/download/example/sample/sample-card-group.ejs rename to src/component/download/deprecated/example/sample/sample-card-group.ejs diff --git a/src/component/download/example/sample/sample-card.ejs b/src/component/download/deprecated/example/sample/sample-card.ejs similarity index 100% rename from src/component/download/example/sample/sample-card.ejs rename to src/component/download/deprecated/example/sample/sample-card.ejs diff --git a/src/component/download/example/sample/sample-default.ejs b/src/component/download/deprecated/example/sample/sample-default.ejs similarity index 100% rename from src/component/download/example/sample/sample-default.ejs rename to src/component/download/deprecated/example/sample/sample-default.ejs diff --git a/src/component/download/example/sample/sample-group-link.ejs b/src/component/download/deprecated/example/sample/sample-group-link.ejs similarity index 100% rename from src/component/download/example/sample/sample-group-link.ejs rename to src/component/download/deprecated/example/sample/sample-group-link.ejs diff --git a/src/component/download/example/sample/sample-lang.ejs b/src/component/download/deprecated/example/sample/sample-lang.ejs similarity index 100% rename from src/component/download/example/sample/sample-lang.ejs rename to src/component/download/deprecated/example/sample/sample-lang.ejs diff --git a/src/component/download/style/_module.scss b/src/component/download/deprecated/style/_module.scss similarity index 100% rename from src/component/download/style/_module.scss rename to src/component/download/deprecated/style/_module.scss diff --git a/src/component/download/style/_scheme.scss b/src/component/download/deprecated/style/_scheme.scss similarity index 92% rename from src/component/download/style/_scheme.scss rename to src/component/download/deprecated/style/_scheme.scss index 9545607ee..9c5c3ace9 100644 --- a/src/component/download/style/_scheme.scss +++ b/src/component/download/deprecated/style/_scheme.scss @@ -12,7 +12,7 @@ @include color.box-shadow(default grey, (legacy:$legacy), all-1-in); #{ns(download__link)} { - @include color.text(title grey, (legacy:$legacy)); + @include color.text(action-high blue-france, (legacy:$legacy)); @include after { @include color.text(action-high blue-france, (legacy:$legacy)); diff --git a/src/component/download/style/_setting.scss b/src/component/download/deprecated/style/_setting.scss similarity index 100% rename from src/component/download/style/_setting.scss rename to src/component/download/deprecated/style/_setting.scss diff --git a/src/component/download/style/_tool.scss b/src/component/download/deprecated/style/_tool.scss similarity index 100% rename from src/component/download/style/_tool.scss rename to src/component/download/deprecated/style/_tool.scss diff --git a/src/component/download/style/module/_download.scss b/src/component/download/deprecated/style/module/_download.scss similarity index 100% rename from src/component/download/style/module/_download.scss rename to src/component/download/deprecated/style/module/_download.scss diff --git a/src/component/download/style/module/_group.scss b/src/component/download/deprecated/style/module/_group.scss similarity index 100% rename from src/component/download/style/module/_group.scss rename to src/component/download/deprecated/style/module/_group.scss diff --git a/src/component/download/style/module/_variants.scss b/src/component/download/deprecated/style/module/_variants.scss similarity index 100% rename from src/component/download/style/module/_variants.scss rename to src/component/download/deprecated/style/module/_variants.scss diff --git a/src/component/download/template/ejs/download.ejs b/src/component/download/deprecated/template/ejs/download.ejs similarity index 98% rename from src/component/download/template/ejs/download.ejs rename to src/component/download/deprecated/template/ejs/download.ejs index a1c05aba2..b3175b370 100644 --- a/src/component/download/template/ejs/download.ejs +++ b/src/component/download/deprecated/template/ejs/download.ejs @@ -24,7 +24,7 @@ * download.attributes (object, optional): Attributs suplémentaires sur le composant %> -<% eval(include('../../../../core/index.ejs')); %> +<% eval(include('../../../../../core/index.ejs')); %> <% let download = locals.download || {}; diff --git a/src/component/download/template/ejs/downloads-group.ejs b/src/component/download/deprecated/template/ejs/downloads-group.ejs similarity index 96% rename from src/component/download/template/ejs/downloads-group.ejs rename to src/component/download/deprecated/template/ejs/downloads-group.ejs index 15b6b556d..ee77435c5 100644 --- a/src/component/download/template/ejs/downloads-group.ejs +++ b/src/component/download/deprecated/template/ejs/downloads-group.ejs @@ -16,7 +16,7 @@ #%> -<% eval(include('../../../../core/index.ejs')); %> +<% eval(include('../../../../../core/index.ejs')); %> <% const downloadsGroup = locals.downloadsGroup || {}; diff --git a/src/component/download/example/deprecated/index.ejs b/src/component/download/example/deprecated/index.ejs new file mode 100644 index 000000000..bcf14b10c --- /dev/null +++ b/src/component/download/example/deprecated/index.ejs @@ -0,0 +1,3 @@ +<%- deprecation(); %> + +<%- include('../../deprecated/example/index') %> diff --git a/src/component/download/example/index.ejs b/src/component/download/example/index.ejs old mode 100755 new mode 100644 index b420c2ce9..e69de29bb --- a/src/component/download/example/index.ejs +++ b/src/component/download/example/index.ejs @@ -1,45 +0,0 @@ -<% -const sample = getSample(include); -const elements = [ - { - title: 'Lien de téléchargement', - path: 'sample-default' - }, - { - title: 'Groupe de liens', - path: 'sample-group-link' - }, - { - title: 'Carte de téléchargement', - path: 'sample-card' - }, - { - title: 'Groupe de cartes', - path: 'sample-card-group' - }, - { - title: 'Fichier en langue étrangère', - path: 'sample-lang' - }, - { - title: 'Utilitaire js', - path: 'sample-assess-js' - }, -]; - -const accordions = []; -for (let element of elements) { - accordions.push({ - label: element.title, - id: uniqueId('download'), - content: include(`./sample/${element.path}`) - }) -} -const data = { - accordions: accordions -} -%> - -<%- section('Téléchargement de fichier', 'Il existe 2 variantes possible pour ce composant. La forme de lien, et la forme de carte.
L\'intitulé du lien doit commencer par ‘Télécharger’.
Le détail est obligatoire et doit conntenir le type (extension du fichier), le poids, la langue (si différente)). Laisser le détail vide si utilisation de l\'utilitaire js de remplissage automatique', 0); %> - -<%- include('../../accordion/template/ejs/accordions-group', {accordionsGroup: data }); %> \ No newline at end of file diff --git a/src/component/download/i18n/fr.yml b/src/component/download/i18n/fr.yml new file mode 100644 index 000000000..878ba2494 --- /dev/null +++ b/src/component/download/i18n/fr.yml @@ -0,0 +1,6 @@ +title: Téléchargement de fichier +description: Ce composant est déprécié. La fonctionnalité "téléchargement de fichier" est maintenant disponible directement sur le composant carte et le composant lien. + +subdir: + title: Autres versions + deprecated: version dépréciée \ No newline at end of file diff --git a/src/component/download/index.js b/src/component/download/index.js deleted file mode 100644 index ce6f7209d..000000000 --- a/src/component/download/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import api from './api.js'; -import { AssessFile } from './script/download/assess-file.js'; -import { DownloadSelector } from './script/download/download-selector'; - -api.download = { - DownloadSelector: DownloadSelector, - AssessFile: AssessFile - -}; - -export default api; diff --git a/src/component/download/index.scss b/src/component/download/index.scss index 33c3540a3..d307fa98d 100644 --- a/src/component/download/index.scss +++ b/src/component/download/index.scss @@ -12,5 +12,5 @@ @import '../../core/index'; @import '../link/index'; -@import 'style/setting'; -@import 'style/tool'; +@import 'deprecated/style/setting'; +@import 'deprecated/style/tool'; diff --git a/src/component/download/main.js b/src/component/download/main.js deleted file mode 100644 index 4fc0dbe6b..000000000 --- a/src/component/download/main.js +++ /dev/null @@ -1,5 +0,0 @@ -import api from './index.js'; - -api.internals.register(api.download.DownloadSelector.DOWNLOAD_ASSESS_FILE, api.download.AssessFile); - -export default api; diff --git a/src/component/download/main.scss b/src/component/download/main.scss index 982e666da..0c7a839b7 100644 --- a/src/component/download/main.scss +++ b/src/component/download/main.scss @@ -14,7 +14,7 @@ @include media-query.order; @import 'index'; -@import 'style/module'; -@import 'style/scheme'; +@import 'deprecated/style/module'; +@import 'deprecated/style/scheme'; @include _download-scheme; diff --git a/src/component/download/script/download/download-selector.js b/src/component/download/script/download/download-selector.js deleted file mode 100644 index 2e51252ef..000000000 --- a/src/component/download/script/download/download-selector.js +++ /dev/null @@ -1,6 +0,0 @@ -import api from '../../api.js'; - -export const DownloadSelector = { - DOWNLOAD_ASSESS_FILE: `${api.internals.ns.attr.selector('assess-file')}`, - DOWNLOAD_DETAIL: `${api.internals.ns.selector('download__detail')}` -}; diff --git a/src/component/link/example/back-to-top/index.ejs b/src/component/link/example/back-to-top/index.ejs new file mode 100644 index 000000000..ec864382e --- /dev/null +++ b/src/component/link/example/back-to-top/index.ejs @@ -0,0 +1,5 @@ +<% const sample = getSample(include); %> + +<%- section('Retour en haut de page', 'Le lien de “retour en haut de page” est une ancre vers un élément dont l’id est "top".
Afin de le faire fonctionner correctement, il est nécessaire d’ajouter l’attribut id (id="top") sur l’élement le plus haut de la page comme le body (<body id="top" ...>) ou les liens d’évitement (<div class="fr-skiplinks" id="top">), afin que le focus de navigation soit lui aussi replacé en haut de page.
Le lien haut de page est un lien classique fr-link composé de l\'icone arrow-up-fill, alignée à gauche, et du label "Haut de page".

Le lien peut être aligné sur la gauche ou la droite du contenu.
Actuce: Pour aligner le lien à droite, l\'insérer dans une <div class="fr-grid-row fr-grid-row--right">.'); %> + +<%- sample('Lien Haut de page - id="top"', './sample/link-back-to-top', {link: {href: '#top'}}, true); %> diff --git a/src/component/link/example/sample/link-back-to-top.ejs b/src/component/link/example/back-to-top/sample/link-back-to-top.ejs similarity index 71% rename from src/component/link/example/sample/link-back-to-top.ejs rename to src/component/link/example/back-to-top/sample/link-back-to-top.ejs index a2bb083c1..3c7a82209 100644 --- a/src/component/link/example/sample/link-back-to-top.ejs +++ b/src/component/link/example/back-to-top/sample/link-back-to-top.ejs @@ -10,4 +10,4 @@ let data = { %> -<%- include('./link-default', {link: data}); %> +<%- include('../../sample/link-default', {link: data}); %> diff --git a/src/component/link/example/download/index.ejs b/src/component/link/example/download/index.ejs new file mode 100755 index 000000000..359d63a1a --- /dev/null +++ b/src/component/link/example/download/index.ejs @@ -0,0 +1,13 @@ +<% const sample = getSample(include); %> + +<%- sample('Lien de téléchargement', './sample/download-default', {}, true); %> + +<%- sample('Groupe de lien de téléchargement', './sample/download-group', {}, true); %> + +<%- sample({title: 'Fichier en langue étrangère', subtitle: 'Indiquer le code langue (ISO 639‑1) du fichier dans l\'attribut "hreflang" et la langue en toute lettre dans le détail'}, './sample/download-default', {link: {href: 'exemple.pdf', detail: 'PDF – 1,81 Mo - Anglais', hreflang: 'en' } }, true); %> + +<%- sample({title: 'Remplissage automatique des détails', subtitle: 'L\'attribut data-fr-assess-file permet de remplir automatiquement le détail avec le type, le poids, et la langue (hreflang) du fichier.'}, './sample/download-default', { link: {detail: ' ', assess: true } }, true); %> + +
+ <%- sample({title: 'Remplissage automatique des détails en Bytes', subtitle: 'Sur une page en anglais, ou toute autre langue utilisant l\'unité "Bytes" plutot que "Octet", ajouter la valeur "bytes" sur l\'attribut : data-fr-assess-file="bytes".'}, './sample/download-default', { link: {label:'Download the french document lorem ipsum', detail: ' ', hreflang: 'fr', assess: 'bytes' } }, true); %> +
diff --git a/src/component/link/example/download/layout-english.ejs b/src/component/link/example/download/layout-english.ejs new file mode 100644 index 000000000..e69de29bb diff --git a/src/component/link/example/download/sample/download-default.ejs b/src/component/link/example/download/sample/download-default.ejs new file mode 100755 index 000000000..501e33437 --- /dev/null +++ b/src/component/link/example/download/sample/download-default.ejs @@ -0,0 +1,14 @@ +<% +let link = locals.link || {}; + +let data = { + download: true, + href: link.href || '/example/img/image.jpg', + detail: link.detail !== false ? link.detail || 'JPG – 61,88 ko' + (link.hreflang === 'en' ? ' – Anglais': '') : '', + label: link.label || 'Télécharger le document lorem ipsum sit dolores amet', + ...link +} + +%> + +<%- include('../../../template/ejs/link', {link: data}); %> diff --git a/src/component/link/example/download/sample/download-group.ejs b/src/component/link/example/download/sample/download-group.ejs new file mode 100755 index 000000000..da3294790 --- /dev/null +++ b/src/component/link/example/download/sample/download-group.ejs @@ -0,0 +1,16 @@ +<% +let link = locals.link || {}; + +let data = { + download: true, + href: link.href || contentPlaceholder(relativeRoot + 'example/img/image.jpg'), + detail: link.detail !== false ? link.detail || 'JPG – 61,88 ko' + (link.hreflang === 'en' ? ' – Anglais': '') : undefined, + label: link.label || 'Télécharger le document lorem ipsum sit dolores amet', + ...link +} + +const links = [data, data, data]; + +%> + +<%- include('../../../template/ejs/links-group', {linksGroup: {links: links}}); %> diff --git a/src/component/link/example/index.ejs b/src/component/link/example/index.ejs index 390638270..7fb8af0b9 100755 --- a/src/component/link/example/index.ejs +++ b/src/component/link/example/index.ejs @@ -20,6 +20,4 @@ <%- sample('Groupe de liens lg', './sample/links-group', { linksGroup: { groupCount: 9, size: 'lg' } }, true); %> -<%- section('Retour en haut de page', 'Le lien de “retour en haut de page” est une ancre vers un élément dont l’id est "top".
Afin de le faire fonctionner correctement, il est nécessaire d’ajouter l’attribut id (id="top") sur l’élement le plus haut de la page comme le body (<body id="top" ...>) ou les liens d’évitement (<div class="fr-skiplinks" id="top">), afin que le focus de navigation soit lui aussi replacé en haut de page.
Le lien haut de page est un lien classique fr-link composé de l\'icone arrow-up-fill, alignée à gauche, et du label "Haut de page".

Le lien peut être aligné sur la gauche ou la droite du contenu.
Actuce: Pour aligner le lien à droite, l\'insérer dans une <div class="fr-grid-row fr-grid-row--right">.'); %> - -<%- sample('Lien Haut de page - id="top"', './sample/link-back-to-top', {link: {href: '#top'}}, true); %> +<%- sample('Groupe de liens en ligne', './sample/links-group', { linksGroup: { groupCount: 9, inline: true} }, true); %> diff --git a/src/component/link/i18n/fr.yml b/src/component/link/i18n/fr.yml new file mode 100644 index 000000000..bd8b1cfdc --- /dev/null +++ b/src/component/link/i18n/fr.yml @@ -0,0 +1,7 @@ +title: Case à cocher +description: La case à cocher permet à l’utilisateur de sélectionner une ou plusieurs options dans une liste. Elle est utilisée pour effectuer des sélections multiples (de 0 à N éléments), ou bien pour permettre un choix binaire, lorsque l’utilisateur peut sélectionner ou désélectionner une seule option. +subdir: + title: Autres versions + download: lien de téléchargement + back-to-top: lien de retour en haut de page + diff --git a/src/component/link/style/_module.scss b/src/component/link/style/_module.scss index ac1663280..898fb7217 100644 --- a/src/component/link/style/_module.scss +++ b/src/component/link/style/_module.scss @@ -4,4 +4,5 @@ //// @import 'module/default'; +@import 'module/download'; @import 'module/group'; diff --git a/src/component/link/style/_scheme.scss b/src/component/link/style/_scheme.scss index 2a6dd9292..629bb98ed 100644 --- a/src/component/link/style/_scheme.scss +++ b/src/component/link/style/_scheme.scss @@ -8,5 +8,19 @@ @mixin _link-scheme($legacy: false) { #{ns(link)} { @include color.text(action-high blue-france, (legacy:$legacy)); + + &__detail { + @include color.text(mention grey, (legacy:$legacy)); + } + } + + #{ns-group(links)} { + li::marker { + @include color.text(action-high blue-france, (legacy:$legacy)); + } + + &--bordered { + @include color.box-shadow(default grey, (legacy:$legacy), all-1-in); + } } } diff --git a/src/component/link/style/module/_download.scss b/src/component/link/style/module/_download.scss new file mode 100644 index 000000000..102106361 --- /dev/null +++ b/src/component/link/style/module/_download.scss @@ -0,0 +1,45 @@ +/// +/// Link Module - download +/// @group link +//// + +#{ns-group(links)}--download #{ns(link)}, +#{ns(link--download)} { + @include relative; + @include nest-link(md, right, download-line, null, false); + @include font-weight(bold); + @include after { + @include margin-bottom(7v); + vertical-align: calc((#{space(3v)} - var(--icon-size)) * 0.5 - #{space(7v)}); + } + + #{ns(link__detail)} { + @include absolute(7v, null, null, 0); + @include text-style(xs); + @include font-weight(regular); + max-width: 100%; + white-space: nowrap; + pointer-events: none; + cursor: text; + overflow: hidden; + text-overflow: ellipsis; + + abbr { + text-decoration: none; + } + } +} + +#{ns-group(links)}--download { + @include enable-list-style; + + > li { + display: block; + } +} + +#{ns-group(links)}--download #{ns(link)}, +#{ns-group(links)} #{ns(link--download)} { + @include margin-bottom(10v); + @include margin-bottom(12v, md); +} diff --git a/src/component/link/style/module/_group.scss b/src/component/link/style/module/_group.scss index 66d4dd497..1f21b05ce 100644 --- a/src/component/link/style/module/_group.scss +++ b/src/component/link/style/module/_group.scss @@ -6,17 +6,24 @@ @use 'module/spacing'; #{ns-group(links)} { - @include disable-list-style; - display: inline-block; - @include margin(0 -2v); + --li-bottom: #{space(2v)}; - > li { + &--inline { + @include disable-list-style; display: inline; - line-height: spacing.space(11v); + @include margin(0 -2v); + + > li { + display: inline; + line-height: spacing.space(11v); + } + + #{ns(link)} { + @include margin(0 2v 4v); + } } #{ns(link)} { - @include margin(0 2v 4v); vertical-align: top; } @@ -27,4 +34,14 @@ &--lg { @include nest-link(lg, null); } + + &__title { + @include title-style(h4); + @include margin(var(--title-spacing)); + } + + &--bordered { + @include padding(6v 6v 2v); + @include padding(8v 8v 2v, md); + } } diff --git a/src/component/link/template/ejs/link.ejs b/src/component/link/template/ejs/link.ejs index fcb898e80..e4b368ef2 100644 --- a/src/component/link/template/ejs/link.ejs +++ b/src/component/link/template/ejs/link.ejs @@ -18,6 +18,8 @@ * link.icon (string, optional) : icon du lien +* link.download (boolean, optional): Si true, lien de téléchargement + * link.iconPlace (string, optional) : emplacement de l'icone si non défini alors que le paramètre icon est défini, bouton avec icone seule, sans label valeurs : @@ -35,8 +37,22 @@ const link = locals.link || {}; let linkClasses = link.classes || []; let linkAttrs = link.attributes || {}; +let label = link.label || 'lorem ipsum'; + const markup = link.markup || 'a'; +if (link.assess === true) { + linkAttrs[`data-${prefix}-assess-file`] = '' +} else if (typeof(link.assess) === 'string') { + linkAttrs[`data-${prefix}-assess-file`] = link.assess +} +if (link.hreflang) linkAttrs.hreflang = link.hreflang; + +if (link.download === true) { + linkAttrs.download = ''; + linkClasses.push(prefix + '-link--download'); +} + linkClasses.push(prefix + '-link'); linkAttrs.id = link.id || uniqueId('link'); @@ -100,8 +116,12 @@ if (link.disabled === true) { } } +if (link.detail) { + label += ` ${link.detail}`; +} + %> <<%= markup %> <%- includeClasses(linkClasses); %> <%- includeAttrs(linkAttrs); %> > -<%- link.label %> +<%- label %> > diff --git a/src/component/link/template/ejs/links-group.ejs b/src/component/link/template/ejs/links-group.ejs index 3eb432a36..652b12a2c 100644 --- a/src/component/link/template/ejs/links-group.ejs +++ b/src/component/link/template/ejs/links-group.ejs @@ -22,6 +22,8 @@ let groupAttrs = linksGroup.attributes || {}; let links = linksGroup.links || []; groupClasses.push(prefix + '-links-group'); +if (linksGroup.inline) groupClasses.push(prefix + '-links-group--inline'); + switch(linksGroup.size) { case 'sm': groupClasses.push(prefix + '-links-group--sm'); diff --git a/src/component/main.js b/src/component/main.js index 6b2d04797..5bd67209c 100644 --- a/src/component/main.js +++ b/src/component/main.js @@ -1,6 +1,7 @@ import api from './api.js'; import './accordion/main.js'; import './button/main.js'; +import './card/main.js'; import './breadcrumb/main.js'; import './toggle/main.js'; import './sidemenu/main.js'; @@ -10,7 +11,6 @@ import './navigation/main.js'; import './tab/main.js'; import './table/main.js'; import './tag/main.js'; -import './download/main.js'; import './header/main.js'; import './display/main.js'; export default api; diff --git a/src/component/tile/style/_scheme.scss b/src/component/tile/style/_scheme.scss index 404a9bce5..7c68f5d9e 100644 --- a/src/component/tile/style/_scheme.scss +++ b/src/component/tile/style/_scheme.scss @@ -8,9 +8,12 @@ @mixin _tile-scheme($legacy: false) { #{ns(tile)} { @include color.box-shadow((default grey) (plain blue-france), (legacy: $legacy), all-1-in bottom-1v-in); - @include color.background(default grey, (legacy: $legacy)); + &__title { + @include color.text(action-high blue-france, (legacy: $legacy)); + } + &--grey { @include color.background(contrast grey, (legacy: $legacy)); } diff --git a/src/core/index.js b/src/core/index.js index cbbbdcdc8..dcdbcb52f 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -23,6 +23,10 @@ import { InjectSvg } from './script/inject/inject-svg'; import { InjectSvgSelector } from './script/inject/inject-svg-selector'; import { Artwork } from './script/artwork/artwork'; import { ArtworkSelector } from './script/artwork/artwork-selector'; +import { AssessSelector } from './script/assess/assess-selector'; +import { AssessFile } from './script/assess/assess-file'; +import { AssessDetail } from './script/assess/assess-detail'; +import { AssessEmission } from './script/assess/assess-emission'; import { RatioSelector } from './script/ratio/ratio-selector.js'; import { Ratio } from './script/ratio/ratio.js'; @@ -50,6 +54,10 @@ api.core = { InjectSvgSelector: InjectSvgSelector, Artwork: Artwork, ArtworkSelector: ArtworkSelector, + AssessFile: AssessFile, + AssessDetail: AssessDetail, + AssessEmission: AssessEmission, + AssessSelector: AssessSelector, Ratio: Ratio, RatioSelector: RatioSelector }; diff --git a/src/core/main.js b/src/core/main.js index 150322d55..c5a57080f 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -3,5 +3,7 @@ import api from './index.js'; api.internals.register(api.core.CollapseSelector.COLLAPSE, api.core.Collapse); api.internals.register(api.core.InjectSvgSelector.INJECT_SVG, api.core.InjectSvg); api.internals.register(api.core.RatioSelector.RATIO, api.core.Ratio); +api.internals.register(api.core.AssessSelector.ASSESS_FILE, api.core.AssessFile); +api.internals.register(api.core.AssessSelector.DETAIL, api.core.AssessDetail); export default api; diff --git a/src/core/script/assess/assess-detail.js b/src/core/script/assess/assess-detail.js new file mode 100644 index 000000000..bae18ba2d --- /dev/null +++ b/src/core/script/assess/assess-detail.js @@ -0,0 +1,19 @@ +import { Instance } from '../api/modules/register/instance.js'; +import { AssessEmission } from './assess-emission'; + +class AssessDetail extends Instance { + static get instanceClassName () { + return 'AssessDetail'; + } + + init () { + this.addDescent(AssessEmission.UPDATE, this.update.bind(this)); + this.ascend(AssessEmission.ADDED); + } + + update (details) { + this.node.innerHTML = details.join(' - '); + } +} + +export { AssessDetail }; diff --git a/src/core/script/assess/assess-emission.js b/src/core/script/assess/assess-emission.js new file mode 100644 index 000000000..810f0463d --- /dev/null +++ b/src/core/script/assess/assess-emission.js @@ -0,0 +1,8 @@ +import ns from '../api/utilities/namespace.js'; + +const AssessEmission = { + UPDATE: ns.emission('assess', 'update'), + ADDED: ns.emission('assess', 'added') +}; + +export { AssessEmission }; diff --git a/src/component/download/script/download/assess-file.js b/src/core/script/assess/assess-file.js similarity index 56% rename from src/component/download/script/download/assess-file.js rename to src/core/script/assess/assess-file.js index 4e8015a9b..243a64612 100644 --- a/src/component/download/script/download/assess-file.js +++ b/src/core/script/assess/assess-file.js @@ -1,7 +1,9 @@ -import api from '../../api.js'; -import { DownloadSelector } from './download-selector'; +import ns from '../api/utilities/namespace.js'; +import { Instance } from '../api/modules/register/instance.js'; +import { AssessEmission } from './assess-emission'; +import inspector from '../api/inspect/inspector.js'; -class AssessFile extends api.core.Instance { +class AssessFile extends Instance { static get instanceClassName () { return 'AssessFile'; } @@ -9,11 +11,11 @@ class AssessFile extends api.core.Instance { init () { this.lang = this.getLang(this.node); this.href = this.getAttribute('href'); - this.hreflang = this.getAttribute('hreflang'); this.file = {}; - this.detail = this.querySelector(DownloadSelector.DOWNLOAD_DETAIL); - this.update(); + this.gather(); + this.addAscent(AssessEmission.ADDED, this.update.bind(this)); + this.addDescent(AssessEmission.ADDED, this.update.bind(this)); } getFileLength () { @@ -25,13 +27,25 @@ class AssessFile extends api.core.Instance { fetch(this.href, { method: 'HEAD', mode: 'cors' }).then(response => { this.length = response.headers.get('content-length') || -1; if (this.length === -1) { - api.inspector.warn('File size unknown: ' + this.href + '\nUnable to get HTTP header: "content-length"'); + inspector.warn('File size unknown: ' + this.href + '\nUnable to get HTTP header: "content-length"'); } - this.update(); + this.gather(); }); } - update () { + mutate (attributeNames) { + if (attributeNames.indexOf('href') !== -1) { + this.href = this.getAttribute('href'); + this.getFileLength(); + } + + if (attributeNames.indexOf('hreflang') !== -1) { + this.hreflang = this.getAttribute('hreflang'); + this.gather(); + } + } + + gather () { // TODO V2: implémenter async if (this.isLegacy) this.length = -1; @@ -40,26 +54,32 @@ class AssessFile extends api.core.Instance { return; } - const details = []; - if (this.detail) { - if (this.href) { - const extension = this.parseExtension(this.href); - if (extension) details.push(extension.toUpperCase()); - } + this.details = []; - if (this.length !== -1) { - details.push(this.bytesToSize(this.length)); - } + if (this.href) { + const extension = this.parseExtension(this.href); + if (extension) this.details.push(extension.toUpperCase()); + } - if (this.hreflang) { - details.push(this.getLangDisplayName(this.hreflang)); - } + if (this.length !== -1) { + this.details.push(this.bytesToSize(this.length)); + } - this.detail.innerHTML = details.join(' - '); + if (this.hreflang) { + this.details.push(this.getLangDisplayName(this.hreflang)); } + + this.update(); + } + + update () { + if (!this.details) return; + this.descend(AssessEmission.UPDATE, this.details); + this.ascend(AssessEmission.UPDATE, this.details); } getLang (elem) { + // todo: ajouter un listener global de changement de langue if (elem.lang) return elem.lang; if (document.documentElement === elem) return window.navigator.language; return this.getLang(elem.parentElement); @@ -81,7 +101,7 @@ class AssessFile extends api.core.Instance { if (bytes === -1) return null; let sizeUnits = ['octets', 'ko', 'Mo', 'Go', 'To']; - if (this.getAttribute(api.internals.ns.attr('assess-file')) === 'bytes') { + if (this.getAttribute(ns.attr('assess-file')) === 'bytes') { sizeUnits = ['bytes', 'KB', 'MB', 'GB', 'TB']; } diff --git a/src/core/script/assess/assess-selector.js b/src/core/script/assess/assess-selector.js new file mode 100644 index 000000000..559f7a839 --- /dev/null +++ b/src/core/script/assess/assess-selector.js @@ -0,0 +1,6 @@ +import ns from '../api/utilities/namespace.js'; + +export const AssessSelector = { + ASSESS_FILE: `${ns.attr.selector('assess-file')}`, + DETAIL: `${ns.attr.selector('assess-file')} [class$="__detail"], ${ns.attr.selector('assess-file')} [class*="__detail "]` +}; diff --git a/tool/example/img/placeholder.32x9.png b/tool/example/img/placeholder.32x9.png new file mode 100644 index 0000000000000000000000000000000000000000..26d1a53a679eefb1dbc1fb16db2800bf2361c343 GIT binary patch literal 4529 zcmeHKjX%@-7yoQ|sF3chD;nuhDY-65Y#!>Dm2`F6t0`_trI3r|xeZ(Sx!oREzpK{o zl5rz$^H|73F@7sc0?0&xMzxciE_1f#~v-5d4=e*zNoY%SegU=zO zmFrgm0F1m2A0z;v3xA?Qmg_;W+|ZW?#R}44zi0pqzDB;NuKwf&0KU55b#VWQgx-n% zrU(q*>}TN?YsOD4KYZE|OW5d{vS*}u!brBN?y_xF+vGE`eb#2bwfmb6=%w0`8h(rvJUrP@mvCKH+&O#9&!ZiI@KMv4L zKDxMVz&Hb^b2$5-glU=$L8l2~+-(^-PulL} zJ}~#0t)4B6N|?Kx%6GC!Y5G{@K0{t>3SC`|T=#cYBzf1>_V5$Lq@j#tmHLXA;ZCQu zAXgWbPnyZ793RcTM8pDY_E0UJg0;wN1R#7Ptj3jpj^AWEeYb({%`Tm>ND7Xwzr?gi z0lO7WOT!=l+D_QXFglDSLH=gsnrXk$Mn5x z887ZEz8i}>c7*sL!VWaLYW*69!K~p{0L5%vt6*{Vbr%!UGr_bOUn}rzJ_x{YMQkFD z>8}UFU`7{96>Lr6%Y^B%R(A~oL>X0`^id!<)2cGoBPtbam4T+7I>*r$af}sxfq?c6 z!Yuz{KIXoJO?7ycq!ir{eXI~!EF9k#;md zf-pR}5eE^q$)Pqx{*D5^uMkw{*g}$W`)otvRe!yd*7M6i@h=FQH6>%Y={~{b<;(B@ z)G*;+9@e6T_X2LnvtJb~R^7rBr}GiqOhYtgtG0_qMuHwouExX=V9a0ZgH!gfVbboW zEj|||p}^joa9g>MTrX_JQ-jm+ZSFBTAdrW22~06-tZRbVCw7c^vHdaYvePmU=!M{A z)IDl0P=&sXb#+{62+9vaYBk>azVPuKyn;Pc!pAV028+K5vp0QsKbbntL4k4|?T&0_ z_eJ~A)}XGwzZ@&i$>M!6aa+(}D-t%}k*GPWYe}1oN#+ZMMcuET*D;^l9)Vf}H{T!^ zS9)@!NzvQ21Evjv7a@aC|ys5-RZA}$~?A7jX>G71%&+M+-&9FBbd5y`mRazlgk96Y)VIl3Z(Qr;5dA}DQ&R|;&xAG%pbGqEj@8c80BB|PVJKOU?;5sFtg z48Wj?c7y-><&rbhW7QM_KF{lY?<|>PZ+gNl2!Ln=9g`4TgX -zuZvsMQP|eUfP5 zFpq7!wh@3Cq?wxJmlle~i~U9<=Jc%El=EF9l45Sid00;ZeGuf)HuJIp{;=!!bBRZ1 zZOA3`bf50UpbLOT)ZU&8X|{*AO+A@qv6DcQH;<=#4~QUmA;?*aY)MxbV}66v$1^>U zbxN5q_B%+dfXES!J|HdAZh@?|JQSW8YDO0er25Fs2duB{%C&A&RgrJP;dQt&X@5Rfp4X%7o{Q4`n9 zi>_*#H<><=X~SxQ27@cL%E=3|`0k*td%~%=?KOW-P2Kl|34I;fYj@*KzIBEd?^c*n z##6M-&N8y1&h5!G)z$l=C;hAJP~?v@o)MHH9A&mAtu`Mf9gDSF2Q-Q#X$$}cF9ldO zaII9T7ozDQMc+e%Rd`rW93iC!^~T8lELNzfDoJ|t_+Xn}N`+J^dXfrXMk;t;<7g(g6P^cy~@ zqm0F{;J`K=n5T?`u%*s$1>}iR3Wd_PW9rVAt^qCG%Rn$qovyLwIcA$D$wum*vDsp) zfKMJUWipVwaL`h<-CtwDbfuhrUR~Yy)*z4jYKI*te~RGgUBHvO%ng;CmEJ*XV6vWW zdl~^~SgKPc93I$zu*l(usKKsRrMbA|1!flc_tHZAH54svD~!l_QjmRJH9J@5`uO6o! Xk0um6N#NW?DB$c|*PM4GC>Vv)IC*86svqj9Qt8SwtU9IK-sdCh3t#TXu-X z8;djBA{QUjSv|w{hB&v~%nz~LU3ax2=X%9GopbMgyS)75*RMBEpT2wZX14qPiq#$R z%>KOAj#@k8^{wa6!}1(=CbWlL=ax9M?e^vE+s|Ljcxh3#IdlKMf5O31{XcV#E$aAM z_2*-uyJSb+RGqKWOc;LG39w{e&owy4-t6jUdqSFJ&F$0;$#zm7Uv9Z~Xr1_nw8Qh} z{kwO+I#Hr>-tRv(%v_t4yB;OQ=_OC7a7@|5d-(05^Hy_gw!iwf-$bDA_`>)4HtQ>^ zf2+?n5a44A+`X5TKj{A5NPhmZbz+;-0%pguvaWICWr6R4p?}r+E%3aVC>eow@87qsb)EiLx0JDM$&SnkzhB@Qi`v;+cLI|^V`9#Z+-{9 zQ#-wGrNMN5iK9L2kGI53-tL)ppyB!Pg9+VDww}q8>+JKM6-+UG!h9^4Ma$B9!pAJp zas`G1N4uMAmt-91yxVq|W6epaNsNn)^~G3s9^}|^IkTnvyT_K3dIxyKJI~La#K;`6 zQ0jtAf5}`v{Xbh87WQ!ZEL{42=R>1xe*dM6|1|gS&=sF&E-`su?2nfRO)g$4^bY-e zHdl|=V8J5A=Vj;jZOvVMb(7cC;%ln>B1(^o z>O}V7JJ%gS$@6ShB%uTj>#{*3u2@jMOyOOv;tr=#eP9W_6Dz d7ZtVqXXKl^koAmZBrB*G@O1TaS?83{1OTde0DS-e literal 0 HcmV?d00001 diff --git a/tool/example/img/placeholder.4x3.png b/tool/example/img/placeholder.4x3.png new file mode 100644 index 0000000000000000000000000000000000000000..ef1a74249fa5a29320713609bfd07c2a4764813f GIT binary patch literal 950 zcmeAS@N?(olHy`uVBq!ia0vp^*+3k?!2~2HCdilqDaPU;cPEB*=VV?2IWDOYo@u_m z3|c@o2Loe!CIbsd2@p#GF#`kh0!9XAAk7F8TfhXD&0fF^X9s{3?w#@Z5>UB@UU_p=u}$Q+5Cyh5>jLO_(pm$m=@&!4i~ZmQjr@XIdAclvHRum9$utGqpWhHKNY z_c?d`)5=6me(&wQ!og&?aOxH{g{C$9E&(i&Ol#ugL>#9vte(#9IzjcotEY~FDV!Us zDk+!xpD1V2Ci~&Rua6IGjbzIhZuYM?duG|^JIiRl!5%Y(rUT(3&z~0k{j#OD;>X_~ z7XFtDnLn0n($^Pz`^{{g-{NP#A5N^+_P%E()aGYNlQL$v}#qx_U@*t;+rj{ zrlk{B+vrbDY2jrN%zg6x=goCtZ zNRgSX)2$}l{P(r=lZ5h}FF$V9tFBga^yu9<`P literal 0 HcmV?d00001 From 76b3a2f2a3d14af6e8a85af429e09fb6160ef48f Mon Sep 17 00:00:00 2001 From: lab9 Date: Tue, 13 Jun 2023 15:28:55 +0200 Subject: [PATCH 02/32] =?UTF-8?q?=F0=9F=8E=89=20feat(tile):=20=C3=A9voluti?= =?UTF-8?q?on=20des=20tuiles=20[DS-2725]=20(#534)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Evolution majeur du composant Tuile :** Nous souhaitons revoir la structure html de la tuile pour étendre les variations de contenu (avec détails, badge, etc), et uniformiser avec les comportements de la Carte (card). Changements apportés : - Ajout d'un niveau d'encapsulation dans la structure html - Ajout d'un wrapper "fr-tile__content" pour englober le contenu - Ajout d'un wrapper "fr-tile__header" pour englober l'image - L'image des tuiles est remplacée par un pictogramme - La classe "fr-tile__img" devient "fr-tile__pictogram" - Son contenu est maintenant un svg "fr-artwork" - Ajout de la possibilité de placer un badge, un tag, un texte de détail, dans le contenu de la tuile - Ajout d'une taille de tuile SM : "fr-tile--sm" **⚠️ Breaking Change** Le snippet de code d'une tuile : ```html ``` Devient : ```html ``` --- src/component/card/style/_scheme.scss | 2 +- src/component/card/style/module/_default.scss | 7 ++ src/component/legacy.scss | 2 +- src/component/link/style/tool/_build.scss | 1 - src/component/main.scss | 2 +- src/component/tile/.package.yml | 7 +- .../tile/deprecated/example/index.ejs | 15 +++ .../example/sample/tile-default.ejs | 16 +++ .../example/sample/tile-horizontal.ejs | 0 .../example/sample/tiles-default.ejs | 0 .../example/sample/tiles-horizontal.ejs | 0 .../tile/deprecated/style/_module.scss | 26 +++++ .../tile/deprecated/template/ejs/tile.ejs | 61 ++++++++++++ .../tile/example/deprecated/index.ejs | 3 + src/component/tile/example/index.ejs | 57 +++++++---- .../tile/example/sample/sample-content.ejs | 11 +++ .../tile/example/sample/sample-enlarge.ejs | 3 + .../example/sample/sample-grid-horizontal.ejs | 22 +++++ .../tile/example/sample/sample-grid.ejs | 21 ++++ .../tile/example/sample/sample-horizontal.ejs | 5 + .../tile/example/sample/sample-no-img.ejs | 9 ++ .../tile/example/sample/sample-sizes.ejs | 5 + .../tile/example/sample/tile-default.ejs | 45 ++++++--- .../example/sample/tile-horizontal-md.ejs | 11 --- .../tile/example/sample/tile-layout.ejs | 40 ++++++++ .../tile/example/sample/tile-vertical-md.ejs | 11 --- .../tile/example/sample/tiles-grid.ejs | 15 +++ .../example/sample/tiles-horizontal-md.ejs | 9 -- .../tile/example/sample/tiles-layout.ejs | 14 +++ .../tile/example/sample/tiles-vertical-md.ejs | 9 -- src/component/tile/i18n/fr.yml | 6 ++ src/component/tile/main.scss | 3 + src/component/tile/style/_module.scss | 1 + src/component/tile/style/_scheme.scss | 6 +- src/component/tile/style/module/_default.scss | 95 ++++++++++-------- src/component/tile/style/module/_sm.scss | 33 +++++++ .../tile/style/module/_variations.scss | 99 ++----------------- src/component/tile/template/ejs/content.ejs | 45 +++++++++ src/component/tile/template/ejs/details.ejs | 15 +++ src/component/tile/template/ejs/end.ejs | 14 +++ src/component/tile/template/ejs/footer.ejs | 10 ++ src/component/tile/template/ejs/header.ejs | 14 +++ src/component/tile/template/ejs/start.ejs | 24 +++++ src/component/tile/template/ejs/tile.ejs | 29 +++--- src/core/template/ejs/icon/icon.ejs | 2 +- 45 files changed, 606 insertions(+), 219 deletions(-) create mode 100755 src/component/tile/deprecated/example/index.ejs create mode 100755 src/component/tile/deprecated/example/sample/tile-default.ejs rename src/component/tile/{ => deprecated}/example/sample/tile-horizontal.ejs (100%) rename src/component/tile/{ => deprecated}/example/sample/tiles-default.ejs (100%) rename src/component/tile/{ => deprecated}/example/sample/tiles-horizontal.ejs (100%) create mode 100644 src/component/tile/deprecated/style/_module.scss create mode 100644 src/component/tile/deprecated/template/ejs/tile.ejs create mode 100644 src/component/tile/example/deprecated/index.ejs create mode 100755 src/component/tile/example/sample/sample-content.ejs create mode 100755 src/component/tile/example/sample/sample-enlarge.ejs create mode 100755 src/component/tile/example/sample/sample-grid-horizontal.ejs create mode 100755 src/component/tile/example/sample/sample-grid.ejs create mode 100755 src/component/tile/example/sample/sample-horizontal.ejs create mode 100755 src/component/tile/example/sample/sample-no-img.ejs create mode 100755 src/component/tile/example/sample/sample-sizes.ejs delete mode 100755 src/component/tile/example/sample/tile-horizontal-md.ejs create mode 100644 src/component/tile/example/sample/tile-layout.ejs delete mode 100755 src/component/tile/example/sample/tile-vertical-md.ejs create mode 100644 src/component/tile/example/sample/tiles-grid.ejs delete mode 100755 src/component/tile/example/sample/tiles-horizontal-md.ejs create mode 100644 src/component/tile/example/sample/tiles-layout.ejs delete mode 100755 src/component/tile/example/sample/tiles-vertical-md.ejs create mode 100644 src/component/tile/i18n/fr.yml create mode 100644 src/component/tile/style/module/_sm.scss create mode 100644 src/component/tile/template/ejs/content.ejs create mode 100644 src/component/tile/template/ejs/details.ejs create mode 100644 src/component/tile/template/ejs/end.ejs create mode 100644 src/component/tile/template/ejs/footer.ejs create mode 100644 src/component/tile/template/ejs/header.ejs create mode 100644 src/component/tile/template/ejs/start.ejs diff --git a/src/component/card/style/_scheme.scss b/src/component/card/style/_scheme.scss index a26cc5dc9..658542510 100644 --- a/src/component/card/style/_scheme.scss +++ b/src/component/card/style/_scheme.scss @@ -12,7 +12,7 @@ @include color.background(default grey, (legacy:$legacy)); &:not(&--no-border):not(&--shadow) { - @include color.box-shadow(default grey, (legacy:$legacy), all-1-out); + @include color.background-image((border default grey) (border default grey) (border default grey) (border default grey), (legacy: $legacy)); } &--grey { diff --git a/src/component/card/style/module/_default.scss b/src/component/card/style/module/_default.scss index 436c473d1..d3b4de5df 100644 --- a/src/component/card/style/module/_default.scss +++ b/src/component/card/style/module/_default.scss @@ -19,6 +19,13 @@ } } + &:not(&--no-border):not(&--shadow) { + background-size: 100% 1px, 1px 100%, 1px 100%, 100% 1px; + background-repeat: no-repeat, no-repeat, no-repeat, no-repeat; + background-position: 100% 100%, 0 0, 100% 0, 100% 0; + @include padding(1px); + } + &--no-icon, &:not(#{ns(enlarge-link)}) { #{ns(card__title a)} { diff --git a/src/component/legacy.scss b/src/component/legacy.scss index 06b32343e..833a0cf68 100644 --- a/src/component/legacy.scss +++ b/src/component/legacy.scss @@ -26,7 +26,6 @@ @import 'summary/legacy'; @import 'table/legacy'; @import 'tag/legacy'; -@import 'tile/legacy'; @import 'alert/legacy'; @import 'notice/legacy'; @import 'radio/legacy'; @@ -40,6 +39,7 @@ @import 'navigation/legacy'; @import 'share/legacy'; @import 'footer/legacy'; +@import 'tile/legacy'; @import 'translate/legacy'; @import 'transcription/legacy'; @import 'input/legacy'; diff --git a/src/component/link/style/tool/_build.scss b/src/component/link/style/tool/_build.scss index 9571a98de..8d0bd2ab1 100644 --- a/src/component/link/style/tool/_build.scss +++ b/src/component/link/style/tool/_build.scss @@ -44,7 +44,6 @@ @mixin _build-link-base { @include set-text-margin(0); @include set-title-margin(0); - @include z-index(over); } @mixin _link-display($display) { diff --git a/src/component/main.scss b/src/component/main.scss index 30573c991..fb97c3272 100644 --- a/src/component/main.scss +++ b/src/component/main.scss @@ -28,7 +28,6 @@ @import 'table/main'; @import 'tag/main'; @import 'download/main'; -@import 'tile/main'; @import 'alert/main'; @import 'notice/main'; @import 'radio/main'; @@ -42,6 +41,7 @@ @import 'navigation/main'; @import 'share/main'; @import 'footer/main'; +@import 'tile/main'; @import 'translate/main'; @import 'transcription/main'; @import 'input/main'; diff --git a/src/component/tile/.package.yml b/src/component/tile/.package.yml index f709021e7..b011e2052 100644 --- a/src/component/tile/.package.yml +++ b/src/component/tile/.package.yml @@ -1,7 +1,10 @@ id: tile title: Tuile -description: La tuile est un raccourci ou point d’entrée qui redirige les utilisateurs vers des pages de contenu. Elle fait généralement partie d'une collection ou liste de tuiles similaires. La tuile n’est jamais présentée de manière isolée. doc: https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/tuile -wrapper: col-8 +wrapper: container style: - core + - link + - button + - badge + - tag \ No newline at end of file diff --git a/src/component/tile/deprecated/example/index.ejs b/src/component/tile/deprecated/example/index.ejs new file mode 100755 index 000000000..e24c36c40 --- /dev/null +++ b/src/component/tile/deprecated/example/index.ejs @@ -0,0 +1,15 @@ +<% const sample = getSample(include); %> + +<%- sample('Tuiles verticales', './sample/tiles-default', {}, true) %> +<%- sample('Tuiles verticales', './sample/tiles-default', {tile:{description: 'Texte M regular 2 lignes max'}}, true) %> +<%- sample('Tuiles verticales', './sample/tiles-default', {tile:{img: false}}, true) %> +<%- sample('Tuiles verticales', './sample/tiles-default', {tile:{description: 'Texte M regular 2 lignes max', img: false}}, true) %> + +<%- sample('Tuiles verticales accentuées', './sample/tiles-default', {tile:{accent:'grey'}}, true) %> + +<%- sample('Tuiles horizontales', './sample/tiles-horizontal', {}, true) %> +<%- sample('Tuiles horizontales', './sample/tiles-horizontal', {tile:{description: 'Texte M regular 2 lignes max'}}, true) %> +<%- sample('Tuiles horizontales', './sample/tiles-horizontal', {tile:{img: false}}, true) %> +<%- sample('Tuiles horizontales', './sample/tiles-horizontal', {tile:{description: 'Texte M regular 2 lignes max', img: false}}, true) %> + +<%- section('Breaking change', 'Les modifieurs "fr-tile--horizontal-md" et "fr-tile--vertical-md" ne sont plus supportés') %> diff --git a/src/component/tile/deprecated/example/sample/tile-default.ejs b/src/component/tile/deprecated/example/sample/tile-default.ejs new file mode 100755 index 000000000..266bf0b08 --- /dev/null +++ b/src/component/tile/deprecated/example/sample/tile-default.ejs @@ -0,0 +1,16 @@ +<% +let tile = locals.tile || {}; +let data = { + title: 'Titre M bold', + enlarge: tile.enlarge !== false, + description: lorem(null, 80), + ...tile +} + +if (tile.img !== false) { + data.img = {name: 'city-hall'}; +} else data.img = undefined; + +%> + +<%- include('../../template/ejs/tile', {tile:data}); %> diff --git a/src/component/tile/example/sample/tile-horizontal.ejs b/src/component/tile/deprecated/example/sample/tile-horizontal.ejs similarity index 100% rename from src/component/tile/example/sample/tile-horizontal.ejs rename to src/component/tile/deprecated/example/sample/tile-horizontal.ejs diff --git a/src/component/tile/example/sample/tiles-default.ejs b/src/component/tile/deprecated/example/sample/tiles-default.ejs similarity index 100% rename from src/component/tile/example/sample/tiles-default.ejs rename to src/component/tile/deprecated/example/sample/tiles-default.ejs diff --git a/src/component/tile/example/sample/tiles-horizontal.ejs b/src/component/tile/deprecated/example/sample/tiles-horizontal.ejs similarity index 100% rename from src/component/tile/example/sample/tiles-horizontal.ejs rename to src/component/tile/deprecated/example/sample/tiles-horizontal.ejs diff --git a/src/component/tile/deprecated/style/_module.scss b/src/component/tile/deprecated/style/_module.scss new file mode 100644 index 000000000..d087a5a03 --- /dev/null +++ b/src/component/tile/deprecated/style/_module.scss @@ -0,0 +1,26 @@ +@use 'module/spacing'; + +#{ns(tile)} { + &__img { + @include display-flex(null, center, center); + flex-shrink: 0; + @include size(20v, 20v); + @include margin(0 auto 6v); + overflow: hidden; + @include hover-brighten-filter; + + > svg { + @include size(100%, 100%); + } + } + + &--horizontal { + #{ns(tile__img)} { + @include size(12v, 12v); + @include margin(0 6v 0 0); + + @include size(20v, 20v, md); + @include margin(0 8v 0 0, md); + } + } +} diff --git a/src/component/tile/deprecated/template/ejs/tile.ejs b/src/component/tile/deprecated/template/ejs/tile.ejs new file mode 100644 index 000000000..fd089a8fa --- /dev/null +++ b/src/component/tile/deprecated/template/ejs/tile.ejs @@ -0,0 +1,61 @@ +<%# +# paramètres tile + +* tile.title (string, required) : titre de la tuile + +* tile.markup (string, optional) : (default: h3) Niveau de titre de la tuile + +* tile.enlarge (boolean, optional) : si true, agrandi la zone de clic à toute la tuile + +* tile.horizontal (boolean, optional) : si true, passe la tuile en mode horizontal + +* tile.horizontalMd (boolean, optional) : si true, passe en mode horizontal en dessous du breakpoint md + +* tile.verticalMd (boolean, optional) : si true, passe en mode vertical en dessous du breakpoint md + +* tile.img (object, optional) : Paramètres de l'image + ** src (string, optional) : url de l'image + ** alt (string, optional) : texte alternatif de l'image + +* tile.description (string, optional) : description de la tuile + +* tile.accent (string, optional) : accentuation du composant + +* tile.classes (array, optional) : Classes suplémentaires sur la tuile + +%> +<% eval(include('../../../../../core/index.ejs')); %> + +<% +let tile = locals.tile || {}; +let classes = tile.classes || []; +const markup = tile.markup || 'h3'; +classes.push(`${prefix}-tile`); + +if (tile.enlarge) classes.push(`${prefix}-enlarge-link`); +if (tile.horizontal !== undefined) { + classes.push(`${prefix}-tile--horizontal`); +} +if (tile.horizontalMd !== undefined) { + classes.push(`${prefix}-tile--horizontal-md`); +} +if (tile.verticalMd !== undefined) { + classes.push(`${prefix}-tile--vertical-md`); +} + +if (tile.accent !== undefined) classes.push(`${prefix}-tile--${tile.accent}`); +%> + +
> +
+ <<%= markup %> class="<%= prefix %>-tile__title"><%- tile.title %>> + <% if(tile.description !== undefined) { %> +

<%= tile.description %>

+ <% } %> +
+ <% if (tile.img !== undefined) { %> +
+ <%- include('../../../../../core/template/ejs/artwork/pictogram.ejs', {pictogram: tile.img}); %> +
+ <% } %> +
diff --git a/src/component/tile/example/deprecated/index.ejs b/src/component/tile/example/deprecated/index.ejs new file mode 100644 index 000000000..bcf14b10c --- /dev/null +++ b/src/component/tile/example/deprecated/index.ejs @@ -0,0 +1,3 @@ +<%- deprecation(); %> + +<%- include('../../deprecated/example/index') %> diff --git a/src/component/tile/example/index.ejs b/src/component/tile/example/index.ejs index f2a926eba..6cd0b7810 100755 --- a/src/component/tile/example/index.ejs +++ b/src/component/tile/example/index.ejs @@ -1,23 +1,46 @@ <% const sample = getSample(include); %> -<%- sample('Tuiles verticales', './sample/tiles-default', {}, true) %> -<%- sample('Tuiles verticales', './sample/tiles-default', {tile:{description: 'Texte M regular 2 lignes max'}}, true) %> -<%- sample('Tuiles verticales', './sample/tiles-default', {tile:{img: false}}, true) %> -<%- sample('Tuiles verticales', './sample/tiles-default', {tile:{description: 'Texte M regular 2 lignes max', img: false}}, true) %> +<% + const elements = [ + { + title: 'Tailles', + path: 'sample-sizes' + }, + { + title: 'Sans image', + path: 'sample-no-img' + }, + { + title: 'Contenu', + path: 'sample-content' + }, + { + title: 'Tuile horizontale', + path: 'sample-horizontal' + }, + { + title: 'Grille de tuiles', + path: 'sample-grid' + }, + { + title: 'Grille de tuiles horizontales', + path: 'sample-grid-horizontal' + }, + ]; -<%- sample('Tuiles verticales accentuées', './sample/tiles-default', {tile:{accent:'grey'}}, true) %> + const accordions = []; -<%- sample('Tuiles verticales, horizontales au dessus du breakpoint md', './sample/tiles-vertical-md', {}, true) %> -<%- sample('Tuiles verticales, horizontales au dessus du breakpoint md', './sample/tiles-vertical-md', {tile:{description: 'Texte M regular 2 lignes max'}}, true) %> -<%- sample('Tuiles verticales, horizontales au dessus du breakpoint md', './sample/tiles-vertical-md', {tile:{img: false}}, true) %> -<%- sample('Tuiles verticales, horizontales au dessus du breakpoint md', './sample/tiles-vertical-md', {tile:{description: 'Texte M regular 2 lignes max', img: false}}, true) %> + for (let element of elements) { + accordions.push({ + label: element.title, + id: uniqueId('tile'), + content: include(`./sample/${element.path}`) + }) + } -<%- sample('Tuiles horizontales', './sample/tiles-horizontal', {}, true) %> -<%- sample('Tuiles horizontales', './sample/tiles-horizontal', {tile:{description: 'Texte M regular 2 lignes max'}}, true) %> -<%- sample('Tuiles horizontales', './sample/tiles-horizontal', {tile:{img: false}}, true) %> -<%- sample('Tuiles horizontales', './sample/tiles-horizontal', {tile:{description: 'Texte M regular 2 lignes max', img: false}}, true) %> + const data = { + accordions: accordions + } + %> -<%- sample('Tuiles horizontales, verticales au dessus du breakpoint md', './sample/tiles-horizontal-md', {}, true) %> -<%- sample('Tuiles horizontales, verticales au dessus du breakpoint md', './sample/tiles-horizontal-md', {tile:{description: 'Texte M regular 2 lignes max'}}, true) %> -<%- sample('Tuiles horizontales, verticales au dessus du breakpoint md', './sample/tiles-horizontal-md', {tile:{img: false}}, true) %> -<%- sample('Tuiles horizontales, verticales au dessus du breakpoint md', './sample/tiles-horizontal-md', {tile:{description: 'Texte M regular 2 lignes max', img: false}}, true) %> +<%- include('../../accordion/template/ejs/accordions-group', {accordionsGroup: data }); %> diff --git a/src/component/tile/example/sample/sample-content.ejs b/src/component/tile/example/sample/sample-content.ejs new file mode 100755 index 000000000..b3cc05d5e --- /dev/null +++ b/src/component/tile/example/sample/sample-content.ejs @@ -0,0 +1,11 @@ +<% const sample = getSample(include); %> + +<%- sample('Tuile verticale avec badge dans le contenu', './tile-default', { tile : { pictogram: true, content: { badge: true } }}, true, './tile-layout', {col: {md:4}}); %> + +<%- sample('Tuile verticale avec tag dans le contenu', './tile-default', { tile : { pictogram: true, content: { tag: true } }}, true, './tile-layout', {col: {md:4}}); %> + +<%- sample('Tuile verticale avec détail', './tile-default', { tile : { pictogram: true, content: { details: true } }}, true, './tile-layout', {col: {md:4}}); %> + +<%- sample('Tuile verticale sm avec détails et badge', './tile-default', { tile : { pictogram: true, size: 'sm', content: { badge: true, details: true } }}, true, './tile-layout', {col: {md:3}}); %> + +<%- sample('Tuile verticale sm avec détails et tag', './tile-default', { tile : { pictogram: true, size: 'sm', content: { tag: true, details: true } }}, true, './tile-layout', {col: {md:3}}); %> diff --git a/src/component/tile/example/sample/sample-enlarge.ejs b/src/component/tile/example/sample/sample-enlarge.ejs new file mode 100755 index 000000000..8efb3c308 --- /dev/null +++ b/src/component/tile/example/sample/sample-enlarge.ejs @@ -0,0 +1,3 @@ +<% const sample = getSample(include); %> + +<%- sample('Tuile verticale sans lien étendu à la tuile', './tile-default', { tile: { pictogram: true, enlarge: false }}, true, './tile-layout', {col: {md:4}}); %> diff --git a/src/component/tile/example/sample/sample-grid-horizontal.ejs b/src/component/tile/example/sample/sample-grid-horizontal.ejs new file mode 100755 index 000000000..e5286b958 --- /dev/null +++ b/src/component/tile/example/sample/sample-grid-horizontal.ejs @@ -0,0 +1,22 @@ +<% const sample = getSample(include); %> + +<% +const tileH = { pictogram: true, horizontal: true, col: {md:'6', lg:'4'}}; +%> +<%- sample('Grilles de tuiles horizontales', './tiles-grid', { tiles : [ + { ...tileH, content: { tag: true }}, + { ...tileH, content: { badge: true }}, + { ...tileH, content: { details: true }}, + { ...tileH, content: { details: true, tag: true }}, + ]}, true, './tiles-layout'); %> + +<% +const tileHSm = { pictogram: true, horizontal: true, size:'sm', col: { sm:'6', md:'4', lg:'3'}}; +%> +<%- sample('Grilles de tuiles horizontales sm', './tiles-grid', { tiles : [ + { ...tileHSm, content: { tag: true }}, + { ...tileHSm, content: { badge: true }}, + { ...tileHSm, content: { details: true }}, + { ...tileHSm, content: { details: true, tag: true }}, + ]}, true, './tiles-layout'); %> + diff --git a/src/component/tile/example/sample/sample-grid.ejs b/src/component/tile/example/sample/sample-grid.ejs new file mode 100755 index 000000000..8442a4e5a --- /dev/null +++ b/src/component/tile/example/sample/sample-grid.ejs @@ -0,0 +1,21 @@ +<% const sample = getSample(include); %> + +<% + const tile = { pictogram: true, col: {md:'6', lg:'4'}}; + %> +<%- sample('Grilles de tuiles verticales', './tiles-grid', { tiles : [ + { ...tile, content: { tag: true }}, + { ...tile, content: { badge: true }}, + { ...tile, content: { details: true }}, + { ...tile, content: { details: true, tag: true }}, + ]}, true, './tiles-layout'); %> + +<% +const tileSm = { pictogram: true, size:'sm', col: {sm:'6', md:'4', lg:'3'}}; +%> +<%- sample('Grilles de tuiles verticales sm', './tiles-grid', { tiles : [ + { ...tileSm, content: { tag: true }}, + { ...tileSm, content: { badge: true }}, + { ...tileSm, content: { details: true }}, + { ...tileSm, content: { details: true, tag: true }}, + ]}, true, './tiles-layout'); %> diff --git a/src/component/tile/example/sample/sample-horizontal.ejs b/src/component/tile/example/sample/sample-horizontal.ejs new file mode 100755 index 000000000..46cc54409 --- /dev/null +++ b/src/component/tile/example/sample/sample-horizontal.ejs @@ -0,0 +1,5 @@ +<% const sample = getSample(include); %> + +<%- sample('Tuile horizontale avec détails et tag', './tile-default', { tile : { pictogram: true, horizontal: true, content: { tag: true, details: true } }}, true, './tile-layout', {col: {md:'6', lg:'4'}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> + +<%- sample('Tuile horizontale sm avec détails et badge', './tile-default', { tile : { pictogram: true, size: 'sm', horizontal: true, content: { badge: true, details: true }}}, true, './tile-layout', {col: { sm:'6', md:'4', lg:'3'}, desc: 'dans une grille sur 3 à 6 colonnes en version desktop'}); %> diff --git a/src/component/tile/example/sample/sample-no-img.ejs b/src/component/tile/example/sample/sample-no-img.ejs new file mode 100755 index 000000000..07060bba8 --- /dev/null +++ b/src/component/tile/example/sample/sample-no-img.ejs @@ -0,0 +1,9 @@ +<% const sample = getSample(include); %> + +<%- sample('Tuile sans image', './tile-default', {tile: {content: {details: true}}}, true, './tile-layout', {col: {md:4}}); %> + +<%- sample('Tuile titre et description', './tile-default', {}, true, './tile-layout', {col: {md:4}}); %> + +<%- sample('Tuile titre et détails', './tile-default', {tile: {content: { description: false, details: true}}}, true, './tile-layout', {col: {md:4}}); %> + +<%- sample('Tuile titre seul', './tile-default', {tile: {content: { description: false}}}, true, './tile-layout', {col: {md:4}}); %> diff --git a/src/component/tile/example/sample/sample-sizes.ejs b/src/component/tile/example/sample/sample-sizes.ejs new file mode 100755 index 000000000..201e24433 --- /dev/null +++ b/src/component/tile/example/sample/sample-sizes.ejs @@ -0,0 +1,5 @@ +<% const sample = getSample(include); %> + +<%- sample('tuile verticale md, taille par défaut', './tile-default', { tile : { pictogram: true }}, true, './tile-layout', {col: {start: 9, md:4}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> + +<%- sample('tuile taille sm', './tile-default', { tile: { pictogram: true, size: 'sm' }}, true, './tile-layout', {col: {start: 6, md:3}, desc: 'dans une grille sur 3 à 4 colonnes en version desktop'}); %> diff --git a/src/component/tile/example/sample/tile-default.ejs b/src/component/tile/example/sample/tile-default.ejs index d1b26072c..459bd0296 100755 --- a/src/component/tile/example/sample/tile-default.ejs +++ b/src/component/tile/example/sample/tile-default.ejs @@ -1,17 +1,40 @@ <% -let tile = locals.tile || {}; -let data = { - title: 'Titre M bold', - href: '#', - enlarge: tile.enlarge !== false, - description: lorem(null, 80), - ...tile +const tile = locals.tile || {}; +const content = tile.content || {}; +const data = { + content: { + title: content.title || 'Intitulé de la tuile', + description: content.description !== false ? content.description || lorem('', 60) : undefined, + }, + size: tile.size, + enlarge: tile.enlarge !== false && tile.footer === undefined, + icon: tile.icon } -if (tile.img !== false) { - data.img = imgData('img/placeholder.1x1.png', 'unrendered'); -} else data.img = undefined; +if (tile.horizontal) { + data.horizontal = tile.horizontal; +} + +if (tile.pictogram === true) { + data.header = {}; + data.header.pictogram = {name: 'city-hall'}; +} + +if (tile.content) { + if (tile.content.details) { + data.content.details = content.details === true ? 'Détail (optionel)' : tile.content.details + } + + if (tile.content.badge) { + data.content.badge = { size: 'sm', label: 'label badge', accent: 'purple-glycine'}; + } + + if (tile.content.tag) { + data.content.tag = { size: 'sm', label: 'label tag'}; + } + +} %> -<%- include('../../template/ejs/tile', {tile:data}); %> +<%- include('../../template/ejs/tile', {tile: data}); %> diff --git a/src/component/tile/example/sample/tile-horizontal-md.ejs b/src/component/tile/example/sample/tile-horizontal-md.ejs deleted file mode 100755 index 075c13e57..000000000 --- a/src/component/tile/example/sample/tile-horizontal-md.ejs +++ /dev/null @@ -1,11 +0,0 @@ -<% -let tile = locals.tile || {}; - -let data = { - ...tile, - horizontalMd: true -} - -%> - -<%- include('./tile-default', {tile:data}); %> diff --git a/src/component/tile/example/sample/tile-layout.ejs b/src/component/tile/example/sample/tile-layout.ejs new file mode 100644 index 000000000..594794202 --- /dev/null +++ b/src/component/tile/example/sample/tile-layout.ejs @@ -0,0 +1,40 @@ +<% + const layout = locals.layout || {}; + const layoutClasses = layout.classes || []; + %> +
> +
+ <% if (locals.title !== undefined && locals.title.length) { %> +

<%= title %>

+ <% } %> + <% if (locals.desc !== undefined && locals.desc.length) { %> +

<%= desc %>

+ <% } %> +
+ <% + if (locals.col) { + %> +
+ <% + const colClasses = col.classes || []; + colClasses.push(`${prefix}-col-${col.start || 12}`); + for (const bp of ['sm', 'md', 'lg', 'xl']) if (col[bp]) colClasses.push(`${prefix}-col-${bp}-${col[bp]}`); + %> +
> + <%- component; %> +
+
+ + <% + } else { + %> + <%- component %> + <% } %> +
+ <% if (locals.snippet !== undefined) { %> +
+ <%- snippet %> +
+ <% } %> +
+
diff --git a/src/component/tile/example/sample/tile-vertical-md.ejs b/src/component/tile/example/sample/tile-vertical-md.ejs deleted file mode 100755 index 3b22d9b36..000000000 --- a/src/component/tile/example/sample/tile-vertical-md.ejs +++ /dev/null @@ -1,11 +0,0 @@ -<% -let tile = locals.tile || {}; -let data = { - ...tile, - horizontal: true, - verticalMd: true -} - -%> - -<%- include('./tile-default', {tile:data}); %> diff --git a/src/component/tile/example/sample/tiles-grid.ejs b/src/component/tile/example/sample/tiles-grid.ejs new file mode 100644 index 000000000..268d03bbd --- /dev/null +++ b/src/component/tile/example/sample/tiles-grid.ejs @@ -0,0 +1,15 @@ +
+ <% + const tiles = locals.tiles || [{}]; + for (const tile of tiles) { + const col = tile.col || { md: 4}; + const colClasses = [`${prefix}-col-${col.start || 12}`]; + for (const bp of ['sm', 'md', 'lg', 'xl']) if (col[bp]) colClasses.push(`${prefix}-col-${bp}-${col[bp]}`); + %> +
> + <%- include('tile-default', { tile: tile }); %> +
+ <% + } + %> +
diff --git a/src/component/tile/example/sample/tiles-horizontal-md.ejs b/src/component/tile/example/sample/tiles-horizontal-md.ejs deleted file mode 100755 index a57b0fe42..000000000 --- a/src/component/tile/example/sample/tiles-horizontal-md.ejs +++ /dev/null @@ -1,9 +0,0 @@ -
- <% - for (let j = 0; j < 4; j++) { - %> -
- <%- include('./tile-horizontal-md', {tile: locals.tile}); %> -
- <% } %> -
diff --git a/src/component/tile/example/sample/tiles-layout.ejs b/src/component/tile/example/sample/tiles-layout.ejs new file mode 100644 index 000000000..a4cc153ff --- /dev/null +++ b/src/component/tile/example/sample/tiles-layout.ejs @@ -0,0 +1,14 @@ +
+ <% if (locals.title !== undefined && locals.title.length) { %> +

<%= title %>

+ <% } %> +
+ <%- component %> +
+ <% if (locals.snippet !== undefined) { %> +
+ <%- snippet %> +
+ <% } %> +
+ diff --git a/src/component/tile/example/sample/tiles-vertical-md.ejs b/src/component/tile/example/sample/tiles-vertical-md.ejs deleted file mode 100755 index e79de00d2..000000000 --- a/src/component/tile/example/sample/tiles-vertical-md.ejs +++ /dev/null @@ -1,9 +0,0 @@ -
- <% - for (let j = 0; j < 4; j++) { - %> -
- <%- include('./tile-vertical-md'); %> -
- <% } %> -
diff --git a/src/component/tile/i18n/fr.yml b/src/component/tile/i18n/fr.yml new file mode 100644 index 000000000..ae2b2f68d --- /dev/null +++ b/src/component/tile/i18n/fr.yml @@ -0,0 +1,6 @@ +title: Tuile +description: La tuile est un raccourci ou point d’entrée qui redirige les utilisateurs vers des pages de contenu. Elle fait généralement partie d'une collection ou liste de tuiles similaires. La tuile n’est jamais présentée de manière isolée. + +subdir: + title: Autres versions + deprecated: version dépréciée diff --git a/src/component/tile/main.scss b/src/component/tile/main.scss index 98dd76e18..56defb48e 100644 --- a/src/component/tile/main.scss +++ b/src/component/tile/main.scss @@ -18,3 +18,6 @@ @import 'style/scheme'; @include _tile-scheme; + +// deprecated +@import 'deprecated/style/module'; diff --git a/src/component/tile/style/_module.scss b/src/component/tile/style/_module.scss index a560a7799..8c025ccb0 100644 --- a/src/component/tile/style/_module.scss +++ b/src/component/tile/style/_module.scss @@ -4,4 +4,5 @@ //// @import 'module/default'; +@import 'module/sm'; @import 'module/variations'; diff --git a/src/component/tile/style/_scheme.scss b/src/component/tile/style/_scheme.scss index 7c68f5d9e..1c97fbbcd 100644 --- a/src/component/tile/style/_scheme.scss +++ b/src/component/tile/style/_scheme.scss @@ -7,8 +7,12 @@ @mixin _tile-scheme($legacy: false) { #{ns(tile)} { - @include color.box-shadow((default grey) (plain blue-france), (legacy: $legacy), all-1-in bottom-1v-in); @include color.background(default grey, (legacy: $legacy)); + @include color.background-image((border active blue-france) (border default grey) (border default grey) (border default grey), (legacy: $legacy)); + + &__title { + @include color.text(title blue-france, (legacy: $legacy)); + } &__title { @include color.text(action-high blue-france, (legacy: $legacy)); diff --git a/src/component/tile/style/module/_default.scss b/src/component/tile/style/module/_default.scss index 2c0cfe3cb..efc32b0ef 100644 --- a/src/component/tile/style/module/_default.scss +++ b/src/component/tile/style/module/_default.scss @@ -5,70 +5,83 @@ #{ns(tile)} { @include relative; - @include display-flex(column-reverse); + @include display-flex(column); @include set-text-margin(0); - @include set-title-margin(0 0 2v); + @include set-title-margin(0 0 1v); + background-size: 100% 4px, 1px 100%, 1px 100%, 100% 1px; + background-repeat: no-repeat, no-repeat, no-repeat, no-repeat; + background-position: 100% 100%, 0 0, 100% 0, 100% 0; + @include padding(6v 6v 7v); + @include padding(8v 8v 9v, md); + text-align: center; - /** - * Forcer la hauteur à 100% pour que les tuiles aient la même hauteur dans le contexte de la grille - */ #{ns(grid-row)} & { @include size(null, 100%); } - &__link { - display: inline-flex; - @include disable-underline; - @include size(100%); - } + @include hover-brighten(#{&}#{ns(enlarge-link)}, #{&}__pictogram); - @include hover-brighten(#{&}#{ns(enlarge-link)}, #{&}__img); + &__header { + order: 1; + @include margin-bottom(4v); + } - /** - * Conteneur pour l'image, on force les dimensions à 80x80 tout en permettant de mettre une image - * ne respectant pas cette taille : - * Si l'image est plus grande, elle sera croppée afin de ne jamais dépasser 80x80. - * Si l'image est plus petite, elle sera centrée, en hauteur, en largeur ou bien les deux. - */ - &__img { + &__pictogram { @include display-flex(null, center, center); flex-shrink: 0; @include size(20v, 20v); - @include margin(8v auto 0); + @include margin(0 auto); overflow: hidden; - @include hover-brighten-filter; - /** - * Dans le cas d'un svg inline sans largeur et hauteur spécifiées, on lui attribue une largeur de 100%. - */ > svg { - @include size(100%); + @include size(100%, 100%); } } - /** - * Partie de la tuile contenant le titre (obligatoire) et la description (optionnel) - */ - @include body { - @include display-flex(column, center, center); - flex-grow: 1; - @include padding(4v); - @include padding(6v,md); - text-align: center; + &__content { + @include display-flex(column, center, space-between); + @include height(100%); + } + + &__body { + @include height(100%); + order: 2; + flex: 1 1 auto; } - /** - * Titre de la tuile - */ @include title { - @include text-style(md); - @include font-weight(bold); + @include title-style(h6); + @include margin-bottom(1v); + order: 2; } - /** - * Description de la tuile - */ &__desc { @include text-style(md); + flex: 1 1 auto; + order: 3; + } + + &__start { + order: 1; + @include margin-bottom(4v); + + #{ns(badges-group)}, + #{ns(tags-group)} { + @include margin-bottom(-2v); + } + } + + &__detail { + @include text-style(xs); + @include display-flex(row, flex-start); + @include margin-bottom(0); + @include margin-top(3v); + order: 4; + + @include has-icon { + @include icon-size(sm, before) { + @include margin-right(2v); + } + } } } diff --git a/src/component/tile/style/module/_sm.scss b/src/component/tile/style/module/_sm.scss new file mode 100644 index 000000000..75ed8db6f --- /dev/null +++ b/src/component/tile/style/module/_sm.scss @@ -0,0 +1,33 @@ +#{ns(tile--sm)} { + @include padding(6v 6v 7v, md); + + #{ns(tile)} { + &__title { + @include text-style(md); + } + + &__desc { + @include text-style(sm); + } + + &__start { + @include margin-bottom(3v); + } + + &__pictogram { + @include size(14v, 14v); + } + } + + &#{ns(tile--horizontal)} { + #{ns(tile)} { + &__header { + @include margin-right(6v); + } + + &__pictogram { + @include size(10v, 10v); + } + } + } +} diff --git a/src/component/tile/style/module/_variations.scss b/src/component/tile/style/module/_variations.scss index 520efa27e..ffd7e93b0 100644 --- a/src/component/tile/style/module/_variations.scss +++ b/src/component/tile/style/module/_variations.scss @@ -10,103 +10,20 @@ **/ #{ns(tile)} { &--horizontal { - flex-direction: row-reverse; - align-items: center; + flex-direction: row; + align-items: flex-start; + text-align: left; - #{ns(tile__img)} { - @include size(12v, 12v); - @include margin(6v 0 6v 6v); - - @include size(20v, 20v, md); - @include margin(8v 0 8v 8v, md); + #{ns(tile__header)} { + @include margin-right(8v); } - #{ns(tile__body)} { - align-items: flex-start; - @include padding(0); - @include margin(6v); - @include margin(8v, md); - text-align: left; + #{ns(tile__pictogram)} { + @include size(16v, 16v); } - } - /** - * Modificateur vertical à partir du breakpoint md -> horizontal en dessous du breakpoint md - **/ - &--vertical-md { - flex-direction: row-reverse; - align-items: center; - - #{ns(tile__img)} { - @include size(12v, 12v); - @include margin(6v 0 6v 6v); - - @include size(20v, 20v, md); - @include margin(8v auto 0, md); - } - - #{ns(tile__body)} { + #{ns(tile__content)} { align-items: flex-start; - @include padding(0); - @include margin(6v); - text-align: left; - - @include respond-from(md) { - align-items: center; - @include padding(6v); - @include margin(0); - text-align: center; - } - } - - @include respond-from(md) { - flex-direction: column-reverse; - align-items: initial; - } - } - - /** - * Modificateur horizontal à partir du breakpoint md -> vertical en dessous du breakpoint md - **/ - &--horizontal-md { - flex-direction: column-reverse; - - #{ns(tile__img)} { - @include size(20v, 20v); - @include margin(8v auto 0); - - + #{ns(tile__body)} { - min-height: initial; - - @include respond-from(md) { - @include padding(0); - @include margin(8v); - min-height: spacing.space(20v); - } - } - - @include respond-from(md) { - @include margin(8v 0 8v 8v); - } - } - - #{ns(tile__body)} { - align-items: center; - @include padding(4v); - @include margin(0); - text-align: center; - - @include respond-from(md) { - align-items: flex-start; - @include padding(0); - @include margin(8v); - text-align: left; - } - } - - @include respond-from(md) { - flex-direction: row-reverse; - align-items: center; } } } diff --git a/src/component/tile/template/ejs/content.ejs b/src/component/tile/template/ejs/content.ejs new file mode 100644 index 000000000..e5e70d6d6 --- /dev/null +++ b/src/component/tile/template/ejs/content.ejs @@ -0,0 +1,45 @@ +<%# +# paramètres du contenu principal de la carte + +* content.title (string, required) : Titre de la carte + +* content.description (string, optional) : Description + +* content.badgesGroup (array, optional) : Groupe de badges (voir badge) + +* content.tagsGroup (array, optional) : Groupe de tags (voir tag) + +* content.details (array, optional) : Détails + +* content.markup (string, optional) : (défaut : h3) niveau de titre + +%> +<% +let start = {}; + +const markup = content.markup || 'h3'; + +if (content.badgesGroup) start.badgesGroup = content.badgesGroup; +if (content.tagsGroup) start.tagsGroup = content.tagsGroup; +if (content.tag) start.tag = content.tag; +if (content.badge) start.badge = content.badge; + +%> + +
+ <<%= markup %> class="<%= prefix %>-tile__title"> + <%- content.title %> + > + + <% if (content.description !== undefined) { %> +

<%- content.description %>

+ <% } %> + + <% if (content.details !== undefined) { %> + <%- include('details', { details: content.details }); %> + <% } %> + + <% if (Object.keys(start).length) { %> + <%- include('start', {start: start }); %> + <% } %> +
diff --git a/src/component/tile/template/ejs/details.ejs b/src/component/tile/template/ejs/details.ejs new file mode 100644 index 000000000..d441ad2fd --- /dev/null +++ b/src/component/tile/template/ejs/details.ejs @@ -0,0 +1,15 @@ +<%# +# paramètres des détails de la tuile + +* details (array, required) : collection d'objet définissant les détails + +* details[].label (string, required) : Intitulé du détail + +* icon (string, optionnal) : nom de l'icon + +%> + +<% + const detailClasses = [`${prefix}-tile__detail`]; +%> +

><%- details %>

diff --git a/src/component/tile/template/ejs/end.ejs b/src/component/tile/template/ejs/end.ejs new file mode 100644 index 000000000..ebc86f762 --- /dev/null +++ b/src/component/tile/template/ejs/end.ejs @@ -0,0 +1,14 @@ +<%# +# paramètres de la partie end du contenu principal de la tuile, placé après titre et description + +* end.details (array, optional) : Détails + +%> + +
+ + <% if (end.details !== undefined) { %> + <%- include('details', { details: end.details }); %> + <% } %> + +
diff --git a/src/component/tile/template/ejs/footer.ejs b/src/component/tile/template/ejs/footer.ejs new file mode 100644 index 000000000..0c2f7915f --- /dev/null +++ b/src/component/tile/template/ejs/footer.ejs @@ -0,0 +1,10 @@ +<%# +# paramètres de la zone d'action + +* footer.buttonsGroup (object, optionnal) : paramètres de configuration d'un groupe de boutons + +%> + + diff --git a/src/component/tile/template/ejs/header.ejs b/src/component/tile/template/ejs/header.ejs new file mode 100644 index 000000000..a222af42c --- /dev/null +++ b/src/component/tile/template/ejs/header.ejs @@ -0,0 +1,14 @@ +<%# +# paramètres de l'en-tête de la tuile + +* header.pictogram (object, optional) : paramètres du pictogram + +%> + +
+ <% if (header.pictogram) { %> +
+ <%- include('../../../../core/template/ejs/artwork/pictogram.ejs', {pictogram: header.pictogram}); %> +
+ <% } %> +
diff --git a/src/component/tile/template/ejs/start.ejs b/src/component/tile/template/ejs/start.ejs new file mode 100644 index 000000000..12f4a2b89 --- /dev/null +++ b/src/component/tile/template/ejs/start.ejs @@ -0,0 +1,24 @@ +<%# +# paramètres de la partie start du contenu principal de la carte, placés avant titre et description + +* start.badgesGroup (object, optional) : Groupe de badges (voir badge) + +* start.tagsGroup (object, optional) : Groupe de tags (voir tag) + +* start.tag (object, optional) : tag seul (voir tag) + +* start.badge (object, optional) : badge seul (voir tag) + +%> + +
+ + <% if (start.badge) { %> + <%- include('../../../badge/template/ejs/badge', {badge: start.badge }); %> + <% } %> + + <% if (start.tag) { %> + <%- include('../../../tag/template/ejs/tag', {tag: start.tag }); %> + <% } %> + +
diff --git a/src/component/tile/template/ejs/tile.ejs b/src/component/tile/template/ejs/tile.ejs index 36a466b2c..43f80c74c 100644 --- a/src/component/tile/template/ejs/tile.ejs +++ b/src/component/tile/template/ejs/tile.ejs @@ -7,15 +7,15 @@ * tile.enlarge (boolean, optional) : si true, agrandi la zone de clic à toute la tuile +* tile.size (string, optionnal) : Taille de la tuile ("md" - default | "sm"). + * tile.horizontal (boolean, optional) : si true, passe la tuile en mode horizontal * tile.horizontalMd (boolean, optional) : si true, passe en mode horizontal en dessous du breakpoint md * tile.verticalMd (boolean, optional) : si true, passe en mode vertical en dessous du breakpoint md -* tile.img (object, optional) : Paramètres de l'image - ** src (string, optional) : url de l'image - ** alt (string, optional) : texte alternatif de l'image +* tile.pictogram (object, optional) : Paramètres d'atrwork ou d'icone * tile.description (string, optional) : description de la tuile @@ -30,12 +30,19 @@ <% let tile = locals.tile || {}; +const content = tile.content || {}; let classes = tile.classes || []; const attributes = tile.attributes || {}; attributes.id = tile.id || uniqueId('tile'); const markup = tile.markup || 'h3'; classes.push(`${prefix}-tile`); +switch (tile.size) { + case 'sm': + classes.push(`${prefix}-tile--sm`); + break; +} + if (tile.enlarge) classes.push(`${prefix}-enlarge-link`); if (tile.horizontal !== undefined) { classes.push(`${prefix}-tile--horizontal`); @@ -51,15 +58,15 @@ if (tile.accent !== undefined) classes.push(`${prefix}-tile--${tile.accent}`); %>
<%- includeAttrs(attributes) %>> -
- <<%= markup %> class="<%= prefix %>-tile__title"><%- tile.title %>> - <% if(tile.description !== undefined) { %> -

<%= tile.description %>

+ +
+ <%- include('content', { content: tile.content}) %> + <% if (tile.footer !== undefined) { %> + <%- include('footer', { footer: tile.footer}) %> <% } %>
- <% if (tile.img !== undefined) { %> -
- <%- include('../../../../core/template/ejs/media/responsive-img.ejs', {media:tile.img}); %> -
+ + <% if (tile.header !== undefined) { %> + <%- include('header.ejs', {header: tile.header}) %> <% } %>
diff --git a/src/core/template/ejs/icon/icon.ejs b/src/core/template/ejs/icon/icon.ejs index 92069528c..ccf93070d 100644 --- a/src/core/template/ejs/icon/icon.ejs +++ b/src/core/template/ejs/icon/icon.ejs @@ -1,7 +1,7 @@ <%# # paramètres icon -* icon.icon (string, required): nom de l'icone +* icon.name (string, required): nom de l'icone * icon.size (string, required) [default: 'md']: taille de l'icone (sm|md|lg) From 0b898dda9e04b5a6f383fff484d2c57cd78396d4 Mon Sep 17 00:00:00 2001 From: Keryan SANIE Date: Thu, 15 Jun 2023 17:01:44 +0200 Subject: [PATCH 03/32] =?UTF-8?q?=E2=9C=A8=20feat(tile):=20Ajout=20ic?= =?UTF-8?q?=C3=B4ne=20fl=C3=A8che,=20=C3=A9tat=20d=C3=A9sactiv=C3=A9,=20ic?= =?UTF-8?q?one=20lien=20externe,=20tuile=20de=20t=C3=A9l=C3=A9chargement?= =?UTF-8?q?=20[DS-3243]=20(#602)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les tuiles peuvent maintenant être de type téléchargement (comme les cartes) - Les tuiles de téléchargement sont par défaut horizontales - Le détail de la tuile de téléchargement est obligatoire et il peut être rempli automatiquement en fonction du fichier à télécharger en plaçant à l'attribut "data-fr-assess-file" sur le lien (comme pour carte) Les tuiles ont maintenant par défaut une icone. - arrow-right (par défaut) - external-link (en target="_blank") - download (avec la classe fr-tile--download) Les tuiles désactivées (a sans href) ont à présent: - la bordure bottom en grise - l'icone et le titre en gris Ajout des classes "fr-tile--vertical@md" et "fr-tile--vertical@lg" pour passer une tuile horizontale, ou download, en vertical à partir des breakpoints md et lg --- .../card/example/deprecated/index.ejs | 3 + src/component/card/example/download/index.ejs | 4 - .../download/sample/sample-content.ejs | 8 +- .../download/sample/sample-horizontal.ejs | 4 - .../example/download/sample/sample-img.ejs | 10 +- .../example/download/sample/sample-no-img.ejs | 4 +- .../example/download/sample/sample-sizes.ejs | 10 +- src/component/card/example/index.ejs | 138 +++++++++--------- src/component/card/i18n/fr.yml | 3 +- src/component/main.js | 1 + src/component/tile/.package.yml | 8 +- src/component/tile/api.js | 2 + src/component/tile/example/download/index.ejs | 7 + src/component/tile/example/index.ejs | 4 + .../tile/example/sample/sample-content.ejs | 8 +- .../example/sample/sample-grid-horizontal.ejs | 14 +- .../tile/example/sample/sample-grid.ejs | 12 +- .../tile/example/sample/sample-horizontal.ejs | 10 +- .../tile/example/sample/sample-icon.ejs | 5 + .../tile/example/sample/sample-no-img.ejs | 8 +- .../tile/example/sample/sample-sizes.ejs | 4 +- .../tile/example/sample/tile-default.ejs | 11 +- src/component/tile/i18n/fr.yml | 1 + src/component/tile/index.js | 10 ++ src/component/tile/index.scss | 1 + src/component/tile/main.js | 6 + .../tile/script/tile/tile-download.js | 18 +++ .../tile/script/tile/tile-selector.js | 6 + src/component/tile/style/_module.scss | 1 + src/component/tile/style/_scheme.scss | 23 ++- src/component/tile/style/_tool.scss | 84 +++++++++++ src/component/tile/style/module/_default.scss | 47 +++++- .../tile/style/module/_download.scss | 10 ++ src/component/tile/style/module/_sm.scss | 20 ++- .../tile/style/module/_variations.scss | 27 ++-- src/component/tile/template/ejs/content.ejs | 23 ++- src/component/tile/template/ejs/tile.ejs | 32 +++- 37 files changed, 418 insertions(+), 169 deletions(-) create mode 100644 src/component/card/example/deprecated/index.ejs delete mode 100644 src/component/card/example/download/sample/sample-horizontal.ejs create mode 100644 src/component/tile/api.js create mode 100644 src/component/tile/example/download/index.ejs create mode 100755 src/component/tile/example/sample/sample-icon.ejs create mode 100644 src/component/tile/index.js create mode 100644 src/component/tile/main.js create mode 100644 src/component/tile/script/tile/tile-download.js create mode 100644 src/component/tile/script/tile/tile-selector.js create mode 100644 src/component/tile/style/_tool.scss create mode 100644 src/component/tile/style/module/_download.scss diff --git a/src/component/card/example/deprecated/index.ejs b/src/component/card/example/deprecated/index.ejs new file mode 100644 index 000000000..bcf14b10c --- /dev/null +++ b/src/component/card/example/deprecated/index.ejs @@ -0,0 +1,3 @@ +<%- deprecation(); %> + +<%- include('../../deprecated/example/index') %> diff --git a/src/component/card/example/download/index.ejs b/src/component/card/example/download/index.ejs index 73a857997..9da63b6cb 100644 --- a/src/component/card/example/download/index.ejs +++ b/src/component/card/example/download/index.ejs @@ -19,10 +19,6 @@ title: 'Contenu', path: 'sample-content' }, - { - title: 'Carte horizontale', - path: 'sample-horizontal' - }, ]; const accordions = []; diff --git a/src/component/card/example/download/sample/sample-content.ejs b/src/component/card/example/download/sample/sample-content.ejs index abe6689e4..7fa99cc57 100644 --- a/src/component/card/example/download/sample/sample-content.ejs +++ b/src/component/card/example/download/sample/sample-content.ejs @@ -1,9 +1,9 @@ <% const sample = getSample(include); %> -<%- sample('Carte de téléchargement, cas maximum', './card-download', { card : { content: { details: ['icon'], badges: true } } }, true, '../../sample/card-layout', {col: {sm: 6}}); %> +<%- sample('Carte de téléchargement, cas maximum', './card-download', { card : { content: { details: ['icon'], badges: true } } }, true, '../../sample/card-layout', {}); %> -<%- sample('Carte de téléchargement, cas minimum', './card-download', { card : { img: false, content: { description: false } } }, true, '../../sample/card-layout', {col: {sm: 6}}); %> +<%- sample('Carte de téléchargement, cas minimum', './card-download', { card : { img: false, content: { description: false } } }, true, '../../sample/card-layout', {}); %> -<%- sample('Carte de téléchargement, avec tags', './card-download', { card : { content: { tags: true} }}, true, '../../sample/card-layout', {col: {sm: 6}}); %> +<%- sample('Carte de téléchargement, avec tags', './card-download', { card : { content: { tags: true} }}, true, '../../sample/card-layout', {}); %> -<%- sample('Carte de téléchargement, avec remplissage automatique des détails', './card-download', { card : { content: { assess: true} }}, true, '../../sample/card-layout', {col: {sm: 6}, desc: 'L\'attribut data-fr-assess-file permet de remplir automatiquement le detail depuis les informations du fichier (extension, poids, langue)'}); %> +<%- sample('Carte de téléchargement, avec remplissage automatique des détails', './card-download', { card : { content: { assess: true} }}, true, '../../sample/card-layout', {desc: 'L\'attribut data-fr-assess-file permet de remplir automatiquement le detail depuis les informations du fichier (extension, poids, langue)'}); %> diff --git a/src/component/card/example/download/sample/sample-horizontal.ejs b/src/component/card/example/download/sample/sample-horizontal.ejs deleted file mode 100644 index bb06ba2f0..000000000 --- a/src/component/card/example/download/sample/sample-horizontal.ejs +++ /dev/null @@ -1,4 +0,0 @@ -<% const sample = getSample(include); %> - -<%- sample('Carte de téléchargement sm horizontale', './card-download', { card : { size: 'sm', horizontal: true }}, true, '../../sample/card-layout', {col: {sm:6}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> -<%- sample('Carte de téléchargement md horizontale', './card-download', { card : { size: 'md', horizontal: true }}, true, '../../sample/card-layout', {col: {sm:6}, desc: 'dans une grille sur 6 à 8 colonnes en version desktop'}); %> diff --git a/src/component/card/example/download/sample/sample-img.ejs b/src/component/card/example/download/sample/sample-img.ejs index 62c265be2..39c648401 100644 --- a/src/component/card/example/download/sample/sample-img.ejs +++ b/src/component/card/example/download/sample/sample-img.ejs @@ -1,9 +1,5 @@ <% const sample = getSample(include); %> -<%- sample('Carte de téléchargement, image 3x4', './card-download', {}, true, '../../sample/card-layout', {col: {sm:6, md: 4}}); %> -<%- sample('Carte de téléchargement, image 4x3', './card-download', { card : { img: imgData('img/placeholder.4x3.png', 'unknown') }}, true, '../../sample/card-layout', {col: {sm:6, md: 4}}); %> -<%- sample('Carte de téléchargement, image 32x9', './card-download', { card : { img: imgData('img/placeholder.32x9.png', 'unknown') }}, true, '../../sample/card-layout', {col: {sm:6, md: 4}}); %> - -<%- sample('Carte de téléchargement horizontale, image 3x4', './card-download', { card : { horizontal: true }}, true, '../../sample/card-layout', {col: {md:6}}); %> -<%- sample('Carte de téléchargement horizontale, image 4x3', './card-download', { card : { horizontal: true, img: imgData('img/placeholder.4x3.png', 'unknown') }}, true, '../../sample/card-layout', {col: {md:6}}); %> -<%- sample('Carte de téléchargement horizontale, image 32x9', './card-download', { card : { horizontal: true, img: imgData('img/placeholder.32x9.png', 'unknown') }}, true, '../../sample/card-layout', {col: {sm:6, md: 4}}); %> +<%- sample('Carte de téléchargement, image 3x4', './card-download', {}, true, '../../sample/card-layout', {}); %> +<%- sample('Carte de téléchargement, image 4x3', './card-download', { card : { img: imgData('img/placeholder.4x3.png', 'unknown') }}, true, '../../sample/card-layout', {}); %> +<%- sample('Carte de téléchargement, image 32x9', './card-download', { card : { img: imgData('img/placeholder.32x9.png', 'unknown') }}, true, '../../sample/card-layout', {}); %> diff --git a/src/component/card/example/download/sample/sample-no-img.ejs b/src/component/card/example/download/sample/sample-no-img.ejs index 1aaa3da4d..1a22cba86 100644 --- a/src/component/card/example/download/sample/sample-no-img.ejs +++ b/src/component/card/example/download/sample/sample-no-img.ejs @@ -1,5 +1,5 @@ <% const sample = getSample(include); %> -<%- sample('Carte de téléchargement, sans image', './card-download', {card: {img: false}}, true, '../../sample/card-layout', {col: {md:6}}); %> +<%- sample('Carte de téléchargement, sans image', './card-download', {card: {img: false}}, true, '../../sample/card-layout', {}); %> -<%- sample('Carte de téléchargement horizontale, sans image', './card-download', { card : { img: false, horizontal: true }}, true, '../../sample/card-layout', {col: {md:6}}); %> +<%- sample('Carte de téléchargement horizontale, sans image', './card-download', { card : { img: false, horizontal: true }}, true, '../../sample/card-layout', {}); %> diff --git a/src/component/card/example/download/sample/sample-sizes.ejs b/src/component/card/example/download/sample/sample-sizes.ejs index 089dbfa5e..938102ad4 100644 --- a/src/component/card/example/download/sample/sample-sizes.ejs +++ b/src/component/card/example/download/sample/sample-sizes.ejs @@ -1,9 +1,5 @@ <% const sample = getSample(include); %> -<%- sample('Carte de téléchargement sm', './card-download', { card : { size: 'sm' }}, true, '../../sample/card-layout', {col: {sm: 6, md:4}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> -<%- sample('Carte de téléchargement md', './card-download', { card : { size: 'md' }}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 6 à 8 colonnes en version desktop'}); %> -<%- sample('Carte de téléchargement lg', './card-download', { card : { size: 'lg' }}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 8 à 12 colonnes en version desktop'}); %> - -<%- sample('Carte de téléchargement sm horizontal', './card-download', { card : { size: 'sm', horizontal: true}}, true, '../../sample/card-layout', {col: {sm:6}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> -<%- sample('Carte de téléchargement md horizontal', './card-download', { card : { size: 'md', horizontal: true}}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 6 à 8 colonnes en version desktop'}); %> -<%- sample('Carte de téléchargement lg horizontal', './card-download', { card : { size: 'lg', horizontal: true}}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 8 à 12 colonnes en version desktop'}); %> +<%- sample('Carte de téléchargement sm', './card-download', { card : { size: 'sm' }}, true, '../../sample/card-layout', {col: {md:6}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> +<%- sample('Carte de téléchargement md', './card-download', { card : { size: 'md' }}, true, '../../sample/card-layout', {col: {md:8}, desc: 'dans une grille sur 6 à 8 colonnes en version desktop'}); %> +<%- sample('Carte de téléchargement lg', './card-download', { card : { size: 'lg' }}, true, '../../sample/card-layout', {desc: 'dans une grille sur 8 à 12 colonnes en version desktop'}); %> diff --git a/src/component/card/example/index.ejs b/src/component/card/example/index.ejs index b58399114..6b7902c37 100755 --- a/src/component/card/example/index.ejs +++ b/src/component/card/example/index.ejs @@ -1,82 +1,74 @@ <% const sample = getSample(include); %> <% - const elements = [ - { - title: 'Tailles', - path: 'sample-sizes' - }, - { - title: 'Lien non élargi', - path: 'sample-enlarge' - }, - { - title: 'Icône', - path: 'sample-icon' - }, - { - title: 'Variations', - path: 'sample-variations' - }, - { - title: 'Sans image', - path: 'sample-no-img' - }, - { - title: 'Image et ratio', - path: 'sample-img' - }, - /*{ - title: 'Vidéo et ratios', - path: 'sample-vid' - },*/ - { - title: 'En-tête', - path: 'sample-header' - }, - { - title: 'Contenu', - path: 'sample-content' - }, - { - title: 'Desactivé', - path: 'sample-disabled' - }, - { - title: 'Zone d\'action', - path: 'sample-footer' - }, - { - title: 'Carte horizontale', - path: 'sample-horizontal' - }, - { - title: 'Grille de cartes', - path: 'sample-grid' - }, - { - title: 'Grille de cartes horizontales', - path: 'sample-grid-horizontal' - }, - { - title: 'Deprecated', - path: '../../deprecated/example/index' - }, - ]; + const elements = [ + { + title: 'Tailles', + path: 'sample-sizes' + }, + { + title: 'Lien non élargi', + path: 'sample-enlarge' + }, + { + title: 'Icône', + path: 'sample-icon' + }, + { + title: 'Variations', + path: 'sample-variations' + }, + { + title: 'Sans image', + path: 'sample-no-img' + }, + { + title: 'Image et ratio', + path: 'sample-img' + }, + { + title: 'En-tête', + path: 'sample-header' + }, + { + title: 'Contenu', + path: 'sample-content' + }, + { + title: 'Desactivé', + path: 'sample-disabled' + }, + { + title: 'Zone d\'action', + path: 'sample-footer' + }, + { + title: 'Carte horizontale', + path: 'sample-horizontal' + }, + { + title: 'Grille de cartes', + path: 'sample-grid' + }, + { + title: 'Grille de cartes horizontales', + path: 'sample-grid-horizontal' + }, + ]; - const accordions = []; + const accordions = []; - for (let element of elements) { - accordions.push({ - label: element.title, - id: uniqueId('card'), - content: include(`./sample/${element.path}`) - }) - } + for (let element of elements) { + accordions.push({ + label: element.title, + id: uniqueId('card'), + content: include(`./sample/${element.path}`) + }); + } - const data = { - accordions: accordions - } + const data = { + accordions: accordions + } %> <%- include('../../accordion/template/ejs/accordions-group', {accordionsGroup: data }); %> diff --git a/src/component/card/i18n/fr.yml b/src/component/card/i18n/fr.yml index fb9f85fb1..f2b67d576 100644 --- a/src/component/card/i18n/fr.yml +++ b/src/component/card/i18n/fr.yml @@ -4,4 +4,5 @@ doc: https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/carte subdir: title: Carte de téléchargement de fichier description: Ce composant permet aux utilisateurs de télécharger un fichier. - download: Carte de téléchargement \ No newline at end of file + download: Carte de téléchargement + deprecated: Version dépréciée \ No newline at end of file diff --git a/src/component/main.js b/src/component/main.js index 5bd67209c..b88c60a35 100644 --- a/src/component/main.js +++ b/src/component/main.js @@ -11,6 +11,7 @@ import './navigation/main.js'; import './tab/main.js'; import './table/main.js'; import './tag/main.js'; +import './tile/main.js'; import './header/main.js'; import './display/main.js'; export default api; diff --git a/src/component/tile/.package.yml b/src/component/tile/.package.yml index b011e2052..29a9fefe3 100644 --- a/src/component/tile/.package.yml +++ b/src/component/tile/.package.yml @@ -6,5 +6,9 @@ style: - core - link - button - - badge - - tag \ No newline at end of file +script: + - core +example: + style: + - badge + - tag diff --git a/src/component/tile/api.js b/src/component/tile/api.js new file mode 100644 index 000000000..e82954c70 --- /dev/null +++ b/src/component/tile/api.js @@ -0,0 +1,2 @@ +import api from '../api.js'; +export default api; diff --git a/src/component/tile/example/download/index.ejs b/src/component/tile/example/download/index.ejs new file mode 100644 index 000000000..73edc03a9 --- /dev/null +++ b/src/component/tile/example/download/index.ejs @@ -0,0 +1,7 @@ +<% const sample = getSample(include); %> + +<%- sample('Tuile de téléchargement', '../sample/tile-default', { tile : { pictogram: true, download: true, content: { title: 'Télécharger le document XX', downloadable: true, details: true} }}, true, '../sample/tile-layout', {col: {md:6}, desc: 'Ajouter un attribut "download" sur le lien permet de forcer le téléchargement et éviter l\'ouverture dans le navigateur. Ajoutez-y une valeur pour renommer le fichier au téléchargement.'}); %> + +<%- sample('Tuile de téléchargement avec détail renseigné automatiquement', '../sample/tile-default', { tile : { pictogram: true, download: true, content: { href: '../../img/image.jpg', downloadable: true, title: 'Télécharger le document XX', assess: true, details: 'Ce texte est remplacé en js par les informations du fichier, insérer ici les données connues ou laisser vide'} }}, true, '../sample/tile-layout', {col: {md:6}}); %> + +<%- sample('Tuile de téléchargement vertical à partir de md', '../sample/tile-default', { tile : { pictogram: true, download: true, content: { href: '../../img/image.jpg', downloadable: true, title: 'Télécharger le document XX', vertical: 'md'} }}, true, '../sample/tile-layout', {col: {md:6}}); %> diff --git a/src/component/tile/example/index.ejs b/src/component/tile/example/index.ejs index 6cd0b7810..f5056e4a8 100755 --- a/src/component/tile/example/index.ejs +++ b/src/component/tile/example/index.ejs @@ -14,6 +14,10 @@ title: 'Contenu', path: 'sample-content' }, + { + title: 'Icône', + path: 'sample-icon' + }, { title: 'Tuile horizontale', path: 'sample-horizontal' diff --git a/src/component/tile/example/sample/sample-content.ejs b/src/component/tile/example/sample/sample-content.ejs index b3cc05d5e..12fe769ce 100755 --- a/src/component/tile/example/sample/sample-content.ejs +++ b/src/component/tile/example/sample/sample-content.ejs @@ -1,11 +1,11 @@ <% const sample = getSample(include); %> -<%- sample('Tuile verticale avec badge dans le contenu', './tile-default', { tile : { pictogram: true, content: { badge: true } }}, true, './tile-layout', {col: {md:4}}); %> +<%- sample('Tuile verticale avec badge dans le contenu', './tile-default', { tile : { pictogram: true, content: { badge: true, description: true } }}, true, './tile-layout', {col: {md:4}}); %> -<%- sample('Tuile verticale avec tag dans le contenu', './tile-default', { tile : { pictogram: true, content: { tag: true } }}, true, './tile-layout', {col: {md:4}}); %> +<%- sample('Tuile verticale avec tag dans le contenu', './tile-default', { tile : { pictogram: true, content: { tag: true, description: true } }}, true, './tile-layout', {col: {md:4}}); %> <%- sample('Tuile verticale avec détail', './tile-default', { tile : { pictogram: true, content: { details: true } }}, true, './tile-layout', {col: {md:4}}); %> -<%- sample('Tuile verticale sm avec détails et badge', './tile-default', { tile : { pictogram: true, size: 'sm', content: { badge: true, details: true } }}, true, './tile-layout', {col: {md:3}}); %> +<%- sample('Tuile verticale sm avec détails et badge', './tile-default', { tile : { pictogram: true, size: 'sm', content: { badge: true, details: true, description: true } }}, true, './tile-layout', {col: {md:3}}); %> -<%- sample('Tuile verticale sm avec détails et tag', './tile-default', { tile : { pictogram: true, size: 'sm', content: { tag: true, details: true } }}, true, './tile-layout', {col: {md:3}}); %> +<%- sample('Tuile verticale sm avec détails et tag', './tile-default', { tile : { pictogram: true, size: 'sm', content: { tag: true, details: true, description: true } }}, true, './tile-layout', {col: {md:3}}); %> diff --git a/src/component/tile/example/sample/sample-grid-horizontal.ejs b/src/component/tile/example/sample/sample-grid-horizontal.ejs index e5286b958..b27f3620f 100755 --- a/src/component/tile/example/sample/sample-grid-horizontal.ejs +++ b/src/component/tile/example/sample/sample-grid-horizontal.ejs @@ -4,19 +4,19 @@ const tileH = { pictogram: true, horizontal: true, col: {md:'6', lg:'4'}}; %> <%- sample('Grilles de tuiles horizontales', './tiles-grid', { tiles : [ - { ...tileH, content: { tag: true }}, - { ...tileH, content: { badge: true }}, - { ...tileH, content: { details: true }}, - { ...tileH, content: { details: true, tag: true }}, + { ...tileH, content: { tag: true, description: true, details: true }}, + { ...tileH, content: { badge: true, description: true }}, + { ...tileH, content: { details: true}}, + { ...tileH, content: { }}, ]}, true, './tiles-layout'); %> <% const tileHSm = { pictogram: true, horizontal: true, size:'sm', col: { sm:'6', md:'4', lg:'3'}}; %> <%- sample('Grilles de tuiles horizontales sm', './tiles-grid', { tiles : [ - { ...tileHSm, content: { tag: true }}, - { ...tileHSm, content: { badge: true }}, + { ...tileHSm, content: { tag: true, description: true, details: true }}, + { ...tileHSm, content: { badge: true, description: true }}, { ...tileHSm, content: { details: true }}, - { ...tileHSm, content: { details: true, tag: true }}, + { ...tileHSm, content: { }}, ]}, true, './tiles-layout'); %> diff --git a/src/component/tile/example/sample/sample-grid.ejs b/src/component/tile/example/sample/sample-grid.ejs index 8442a4e5a..4d016da6e 100755 --- a/src/component/tile/example/sample/sample-grid.ejs +++ b/src/component/tile/example/sample/sample-grid.ejs @@ -4,18 +4,18 @@ const tile = { pictogram: true, col: {md:'6', lg:'4'}}; %> <%- sample('Grilles de tuiles verticales', './tiles-grid', { tiles : [ - { ...tile, content: { tag: true }}, - { ...tile, content: { badge: true }}, + { ...tile, content: { tag: true, description: true, details: true }}, + { ...tile, content: { badge: true, description: true }}, { ...tile, content: { details: true }}, - { ...tile, content: { details: true, tag: true }}, + { ...tile, content: { }}, ]}, true, './tiles-layout'); %> <% const tileSm = { pictogram: true, size:'sm', col: {sm:'6', md:'4', lg:'3'}}; %> <%- sample('Grilles de tuiles verticales sm', './tiles-grid', { tiles : [ - { ...tileSm, content: { tag: true }}, - { ...tileSm, content: { badge: true }}, + { ...tileSm, content: { tag: true, description: true, details: true }}, + { ...tileSm, content: { badge: true, description: true }}, { ...tileSm, content: { details: true }}, - { ...tileSm, content: { details: true, tag: true }}, + { ...tileSm, content: { }}, ]}, true, './tiles-layout'); %> diff --git a/src/component/tile/example/sample/sample-horizontal.ejs b/src/component/tile/example/sample/sample-horizontal.ejs index 46cc54409..155ed9013 100755 --- a/src/component/tile/example/sample/sample-horizontal.ejs +++ b/src/component/tile/example/sample/sample-horizontal.ejs @@ -2,4 +2,12 @@ <%- sample('Tuile horizontale avec détails et tag', './tile-default', { tile : { pictogram: true, horizontal: true, content: { tag: true, details: true } }}, true, './tile-layout', {col: {md:'6', lg:'4'}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> -<%- sample('Tuile horizontale sm avec détails et badge', './tile-default', { tile : { pictogram: true, size: 'sm', horizontal: true, content: { badge: true, details: true }}}, true, './tile-layout', {col: { sm:'6', md:'4', lg:'3'}, desc: 'dans une grille sur 3 à 6 colonnes en version desktop'}); %> +<%- sample('Tuile sm horizontale avec détails et badge', './tile-default', { tile : { pictogram: true, size: 'sm', horizontal: true, content: { badge: true, details: true }}}, true, './tile-layout', {col: {md:'6', lg:'4'}, desc: 'dans une grille sur 3 à 6 colonnes en version desktop'}); %> + +<%- sample('Tuile horizontale puis vertical en md', './tile-default', { tile : { pictogram: true, horizontal: true, vertical: 'md', content: { details: true }}}, true, './tile-layout', {col: { md:'6', lg:'4'}, desc: 'dans une grille sur 3 à 6 colonnes en version desktop'}); %> + +<%- sample('Tuile sm horizontale puis vertical en md', './tile-default', { tile : { pictogram: true, size: 'sm', horizontal: true, vertical: 'md', content: { details: true }}}, true, './tile-layout', {col: { md:'6', lg:'4'}, desc: 'dans une grille sur 3 à 6 colonnes en version desktop'}); %> + +<%- sample('Tuile horizontale puis vertical en lg', './tile-default', { tile : { pictogram: true, horizontal: true, vertical: 'lg', content: { details: true }}}, true, './tile-layout', {col: { md:'6', lg:'4'}, desc: 'dans une grille sur 3 à 6 colonnes en version desktop'}); %> + +<%- sample('Tuile sm horizontale puis vertical en lg', './tile-default', { tile : { pictogram: true, size: 'sm', horizontal: true, vertical: 'lg', content: { details: true }}}, true, './tile-layout', {col: { md:'6', lg:'4'}, desc: 'dans une grille sur 3 à 6 colonnes en version desktop'}); %> diff --git a/src/component/tile/example/sample/sample-icon.ejs b/src/component/tile/example/sample/sample-icon.ejs new file mode 100755 index 000000000..6e62da005 --- /dev/null +++ b/src/component/tile/example/sample/sample-icon.ejs @@ -0,0 +1,5 @@ +<% const sample = getSample(include); %> + +<%- sample('Tuile sans icone', './tile-default', { tile : { pictogram: true, icon: false }}, true, './tile-layout', {col: {md:6}}); %> + +<%- sample('Tuile avec icone lien externe', './tile-default', { tile : { pictogram: true, content: { blank: true } }}, true, './tile-layout', {col: {md:6}}); %> diff --git a/src/component/tile/example/sample/sample-no-img.ejs b/src/component/tile/example/sample/sample-no-img.ejs index 07060bba8..3c45056be 100755 --- a/src/component/tile/example/sample/sample-no-img.ejs +++ b/src/component/tile/example/sample/sample-no-img.ejs @@ -1,9 +1,9 @@ <% const sample = getSample(include); %> -<%- sample('Tuile sans image', './tile-default', {tile: {content: {details: true}}}, true, './tile-layout', {col: {md:4}}); %> +<%- sample('Tuile sans image', './tile-default', {}, true, './tile-layout', {col: {md:4}}); %> -<%- sample('Tuile titre et description', './tile-default', {}, true, './tile-layout', {col: {md:4}}); %> +<%- sample('Tuile titre et description', './tile-default', {content: {description: true}}, true, './tile-layout', {col: {md:4}}); %> -<%- sample('Tuile titre et détails', './tile-default', {tile: {content: { description: false, details: true}}}, true, './tile-layout', {col: {md:4}}); %> +<%- sample('Tuile titre et détails', './tile-default', {tile: {content: {details: true}}}, true, './tile-layout', {col: {md:4}}); %> -<%- sample('Tuile titre seul', './tile-default', {tile: {content: { description: false}}}, true, './tile-layout', {col: {md:4}}); %> +<%- sample('Tuile sans image full contenu', './tile-default', {tile: {content: {description:true, badge: true, details: true}}}, true, './tile-layout', {col: {md:4}}); %> diff --git a/src/component/tile/example/sample/sample-sizes.ejs b/src/component/tile/example/sample/sample-sizes.ejs index 201e24433..36f93b447 100755 --- a/src/component/tile/example/sample/sample-sizes.ejs +++ b/src/component/tile/example/sample/sample-sizes.ejs @@ -1,5 +1,5 @@ <% const sample = getSample(include); %> -<%- sample('tuile verticale md, taille par défaut', './tile-default', { tile : { pictogram: true }}, true, './tile-layout', {col: {start: 9, md:4}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> +<%- sample('tuile verticale md, taille par défaut', './tile-default', { tile : { pictogram: true, content: {details: true, description: true} }}, true, './tile-layout', {col: {start: 9, md:4}, desc: 'dans une grille sur 4 à 6 colonnes en version desktop'}); %> -<%- sample('tuile taille sm', './tile-default', { tile: { pictogram: true, size: 'sm' }}, true, './tile-layout', {col: {start: 6, md:3}, desc: 'dans une grille sur 3 à 4 colonnes en version desktop'}); %> +<%- sample('tuile taille sm', './tile-default', { tile: { pictogram: true, size: 'sm', content: {details: true, description: true} }}, true, './tile-layout', {col: {start: 6, md:3}, desc: 'dans une grille sur 3 à 4 colonnes en version desktop'}); %> diff --git a/src/component/tile/example/sample/tile-default.ejs b/src/component/tile/example/sample/tile-default.ejs index 459bd0296..4d2bbb123 100755 --- a/src/component/tile/example/sample/tile-default.ejs +++ b/src/component/tile/example/sample/tile-default.ejs @@ -3,18 +3,24 @@ const tile = locals.tile || {}; const content = tile.content || {}; const data = { content: { + ...content, title: content.title || 'Intitulé de la tuile', - description: content.description !== false ? content.description || lorem('', 60) : undefined, + ...(content.description && {description: content.description === true ? lorem('', 60) : content.description}) }, size: tile.size, enlarge: tile.enlarge !== false && tile.footer === undefined, - icon: tile.icon + icon: tile.icon, + download: tile.download, } if (tile.horizontal) { data.horizontal = tile.horizontal; } +if (tile.vertical) { + data.vertical = tile.vertical; +} + if (tile.pictogram === true) { data.header = {}; data.header.pictogram = {name: 'city-hall'}; @@ -32,7 +38,6 @@ if (tile.content) { if (tile.content.tag) { data.content.tag = { size: 'sm', label: 'label tag'}; } - } %> diff --git a/src/component/tile/i18n/fr.yml b/src/component/tile/i18n/fr.yml index ae2b2f68d..118591c70 100644 --- a/src/component/tile/i18n/fr.yml +++ b/src/component/tile/i18n/fr.yml @@ -4,3 +4,4 @@ description: La tuile est un raccourci ou point d’entrée qui redirige les uti subdir: title: Autres versions deprecated: version dépréciée + download: Tuile de téléchargement diff --git a/src/component/tile/index.js b/src/component/tile/index.js new file mode 100644 index 000000000..b8c2333a1 --- /dev/null +++ b/src/component/tile/index.js @@ -0,0 +1,10 @@ +import api from './api.js'; +import { TileDownload } from './script/tile/tile-download.js'; +import { TileSelector } from './script/tile/tile-selector.js'; + +api.tile = { + TileSelector: TileSelector, + TileDownload: TileDownload +}; + +export default api; diff --git a/src/component/tile/index.scss b/src/component/tile/index.scss index 1ff92f3f6..f655195ac 100644 --- a/src/component/tile/index.scss +++ b/src/component/tile/index.scss @@ -4,3 +4,4 @@ //// @import '../../core/index'; +@import 'style/tool'; diff --git a/src/component/tile/main.js b/src/component/tile/main.js new file mode 100644 index 000000000..ac2c08c38 --- /dev/null +++ b/src/component/tile/main.js @@ -0,0 +1,6 @@ +import api from './index.js'; + +api.internals.register(api.tile.TileSelector.DOWNLOAD, api.tile.TileDownload); +api.internals.register(api.tile.TileSelector.DOWNLOAD_DETAIL, api.core.AssessDetail); + +export default api; diff --git a/src/component/tile/script/tile/tile-download.js b/src/component/tile/script/tile/tile-download.js new file mode 100644 index 000000000..077a98bfd --- /dev/null +++ b/src/component/tile/script/tile/tile-download.js @@ -0,0 +1,18 @@ +import api from '../../api.js'; + +class TileDownload extends api.core.Instance { + static get instanceClassName () { + return 'TileDownload'; + } + + init () { + this.addAscent(api.core.AssessEmission.UPDATE, details => { + this.descend(api.core.AssessEmission.UPDATE, details); + }); + this.addAscent(api.core.AssessEmission.ADDED, () => { + this.descend(api.core.AssessEmission.ADDED); + }); + } +} + +export { TileDownload }; diff --git a/src/component/tile/script/tile/tile-selector.js b/src/component/tile/script/tile/tile-selector.js new file mode 100644 index 000000000..08e14a274 --- /dev/null +++ b/src/component/tile/script/tile/tile-selector.js @@ -0,0 +1,6 @@ +import api from '../../api.js'; + +export const TileSelector = { + DOWNLOAD: api.internals.ns.selector('tile--download'), + DOWNLOAD_DETAIL: `${api.internals.ns.selector('tile--download')} ${api.internals.ns.selector('tile__detail')}` +}; diff --git a/src/component/tile/style/_module.scss b/src/component/tile/style/_module.scss index 8c025ccb0..02a3c7ee5 100644 --- a/src/component/tile/style/_module.scss +++ b/src/component/tile/style/_module.scss @@ -6,3 +6,4 @@ @import 'module/default'; @import 'module/sm'; @import 'module/variations'; +@import 'module/download'; diff --git a/src/component/tile/style/_scheme.scss b/src/component/tile/style/_scheme.scss index 1c97fbbcd..0bf6accaf 100644 --- a/src/component/tile/style/_scheme.scss +++ b/src/component/tile/style/_scheme.scss @@ -4,18 +4,31 @@ //// @use 'module/color'; +@use 'module/disabled'; @mixin _tile-scheme($legacy: false) { #{ns(tile)} { @include color.background(default grey, (legacy: $legacy)); - @include color.background-image((border active blue-france) (border default grey) (border default grey) (border default grey), (legacy: $legacy)); + @include color.background-image((border default grey) (border default grey) (border default grey) (border default grey), (legacy: $legacy)); &__title { - @include color.text(title blue-france, (legacy: $legacy)); - } + @include disabled.selector((can-be-link: true), (legacy: $legacy, text: true, background: true)); - &__title { - @include color.text(action-high blue-france, (legacy: $legacy)); + a { + @include color.text(action-high blue-france, (legacy: $legacy)); + + @include before { + @include color.background-image((border active blue-france), (legacy: $legacy)); + } + + &:not([href]) { + @include disabled.colors((legacy: $legacy, text: true)); + + @include before { + @include color.background-image((border disabled grey), (legacy: $legacy)); + } + } + } } &--grey { diff --git a/src/component/tile/style/_tool.scss b/src/component/tile/style/_tool.scss new file mode 100644 index 000000000..9cf91d79e --- /dev/null +++ b/src/component/tile/style/_tool.scss @@ -0,0 +1,84 @@ +//// +/// Tag Tool +/// @group tag +//// + +@use 'module/color'; +@use 'module/spacing'; + +@mixin build-tile-horizontal() { + flex-direction: row; + align-items: flex-start; + text-align: left; + + #{ns(tile__header)} { + @include margin-right(8v); + @include margin-bottom(0); + } + + #{ns(tile__pictogram)} { + @include size(16v, 16v); + } + + #{ns(tile__content)} { + align-items: flex-start; + } + + &:not(#{ns(tile--no-icon)}) { + #{ns(tile__detail)} { + @include padding-right(8v); + @include margin-bottom(-10v); + @include margin-top(5v); + } + + #{ns(tile__content)} { + @include padding-bottom(10v); + } + + &#{ns(tile--sm)} { + #{ns(tile__detail)} { + @include padding-right(8v); + @include margin-bottom(-8v); + @include margin-top(3v); + } + + #{ns(tile__content)} { + @include padding-bottom(8v); + } + } + } +} + +@mixin build-tile-vertical() { + flex-direction: column; + text-align: center; + align-items: center; + + #{ns(tile__header)} { + @include margin-bottom(4v); + @include margin-right(0 !important); + } + + #{ns(tile__pictogram)} { + @include size(20v, 20v); + } + + #{ns(tile__content)} { + align-items: center; + } + + #{ns(tile__detail)} { + @include margin-top(3v); + } + + &#{ns(enlarge-link)}:not(#{ns(tile--no-icon)}) { + #{ns(tile__content)} { + @include padding-bottom(10v); + } + + #{ns(tile__detail)} { + @include margin-bottom(0); + @include padding-right(0); + } + } +} diff --git a/src/component/tile/style/module/_default.scss b/src/component/tile/style/module/_default.scss index efc32b0ef..aea1f53f8 100644 --- a/src/component/tile/style/module/_default.scss +++ b/src/component/tile/style/module/_default.scss @@ -3,16 +3,18 @@ /// @group tile //// +@use 'module/spacing'; +@use 'module/media-query'; + #{ns(tile)} { @include relative; @include display-flex(column); @include set-text-margin(0); @include set-title-margin(0 0 1v); - background-size: 100% 4px, 1px 100%, 1px 100%, 100% 1px; + background-size: 100% 1px, 1px 100%, 1px 100%, 100% 1px; background-repeat: no-repeat, no-repeat, no-repeat, no-repeat; - background-position: 100% 100%, 0 0, 100% 0, 100% 0; - @include padding(6v 6v 7v); - @include padding(8v 8v 9v, md); + background-position: 0 100%, 0 0, 100% 0, 100% 0; + @include padding(8v 8v 9v); text-align: center; #{ns(grid-row)} & { @@ -39,7 +41,7 @@ } &__content { - @include display-flex(column, center, space-between); + @include display-flex(column, center); @include height(100%); } @@ -51,8 +53,35 @@ @include title { @include title-style(h6); - @include margin-bottom(1v); + @include margin-bottom(2v); order: 2; + + a { + @include before { + background-position: 0 100%; + background-size: 100% spacing.space(1v); + background-repeat: no-repeat; + } + + @include icon(arrow-right-line, md, after) { + @include absolute(null, 6v, 7v); + + @include media-query.respond-from(md) { + @include absolute(null, 8v, 9v); + } + } + + &[target=_blank] { + @include icon(external-link-line, md, after); + } + } + } + + &--no-icon, + &:not(#{ns(enlarge-link)}) { + #{ns(tile__title a)} { + @include after(none); + } } &__desc { @@ -63,7 +92,7 @@ &__start { order: 1; - @include margin-bottom(4v); + @include margin-bottom(3v); #{ns(badges-group)}, #{ns(tags-group)} { @@ -84,4 +113,8 @@ } } } + + &#{ns(enlarge-link)}:not(&--no-icon) &__content { + @include padding-bottom(10v); + } } diff --git a/src/component/tile/style/module/_download.scss b/src/component/tile/style/module/_download.scss new file mode 100644 index 000000000..2a8475411 --- /dev/null +++ b/src/component/tile/style/module/_download.scss @@ -0,0 +1,10 @@ +//// +/// Tile Module : download +/// @group tile +//// + +#{ns(tile--download)} { + #{ns(tile__title a)} { + @include icon(download-line, null, after); + } +} diff --git a/src/component/tile/style/module/_sm.scss b/src/component/tile/style/module/_sm.scss index 75ed8db6f..f11e4fa1b 100644 --- a/src/component/tile/style/module/_sm.scss +++ b/src/component/tile/style/module/_sm.scss @@ -1,9 +1,21 @@ +//// +/// Tile Module : sm +/// @group tile +//// + #{ns(tile--sm)} { - @include padding(6v 6v 7v, md); + @include padding(6v 6v 7v); #{ns(tile)} { &__title { @include text-style(md); + @include margin-bottom(1v); + + a { + @include icon-size(sm, after) { + @include absolute(null, 6v, 7v); + }; + } } &__desc { @@ -11,7 +23,7 @@ } &__start { - @include margin-bottom(3v); + @include margin-bottom(2v); } &__pictogram { @@ -30,4 +42,8 @@ } } } + + &#{ns(enlarge-link)}:not(#{ns(tile--no-icon)}) #{ns(tile__content)} { + @include padding-bottom(8v); + } } diff --git a/src/component/tile/style/module/_variations.scss b/src/component/tile/style/module/_variations.scss index ffd7e93b0..257d74751 100644 --- a/src/component/tile/style/module/_variations.scss +++ b/src/component/tile/style/module/_variations.scss @@ -4,26 +4,23 @@ //// @use 'module/spacing'; +@use 'module/media-query'; -/** - * Modificateur tuile horizontale - **/ #{ns(tile)} { - &--horizontal { - flex-direction: row; - align-items: flex-start; - text-align: left; - - #{ns(tile__header)} { - @include margin-right(8v); - } + &--horizontal, + &--download { + @include build-tile-horizontal(); + } - #{ns(tile__pictogram)} { - @include size(16v, 16v); + &--vertical\@md { + @include media-query.respond-from(md) { + @include build-tile-vertical(); } + } - #{ns(tile__content)} { - align-items: flex-start; + &--vertical\@lg { + @include media-query.respond-from(lg) { + @include build-tile-vertical(); } } } diff --git a/src/component/tile/template/ejs/content.ejs b/src/component/tile/template/ejs/content.ejs index e5e70d6d6..868b7a2eb 100644 --- a/src/component/tile/template/ejs/content.ejs +++ b/src/component/tile/template/ejs/content.ejs @@ -13,11 +13,32 @@ * content.markup (string, optional) : (défaut : h3) niveau de titre +* content.blank (boolean, optional) : Ajoute l'attribut target="_blank" pour ouvrir le lien dans un nouvel onglet + +* content.downloadable (boolean, optional) : Ajoute l'attribut download au lien + +* content.lang (boolean, optional) : Ajoute l'attribut hreflang au lien, pour définir la langue du document lié + +* content.disabled (boolean, optional) : Si true, retire le href du lien pour le désactiver + +* content.assess (String, optional): Si true, remplissage automatique du poid et type de fichier à telecharger %> <% let start = {}; const markup = content.markup || 'h3'; +const href = content.href || '#'; +const attributes = {} +if (content.assess === true) { + attributes[`data-${prefix}-assess-file`] = ''; +} else if (typeof(content.assess) === 'string') { + attributes[`data-${prefix}-assess-file`] = content.assess; +} +if (content.disabled !== true) attributes.href = href; +if (content.lang) attributes.hreflang = content.lang; +if (content.blank === true) attributes.target = '_blank'; +if (content.downloadable === true) attributes.download = ''; +else if (content.downloadable === false) attributes.target = '_blank'; if (content.badgesGroup) start.badgesGroup = content.badgesGroup; if (content.tagsGroup) start.tagsGroup = content.tagsGroup; @@ -28,7 +49,7 @@ if (content.badge) start.badge = content.badge;
<<%= markup %> class="<%= prefix %>-tile__title"> - <%- content.title %> + ><%- content.title %> > <% if (content.description !== undefined) { %> diff --git a/src/component/tile/template/ejs/tile.ejs b/src/component/tile/template/ejs/tile.ejs index 43f80c74c..fb91d779a 100644 --- a/src/component/tile/template/ejs/tile.ejs +++ b/src/component/tile/template/ejs/tile.ejs @@ -7,6 +7,8 @@ * tile.enlarge (boolean, optional) : si true, agrandi la zone de clic à toute la tuile +* tile.download (boolean, optional) : si true, passe la tuile en mode téléchargement + * tile.size (string, optionnal) : Taille de la tuile ("md" - default | "sm"). * tile.horizontal (boolean, optional) : si true, passe la tuile en mode horizontal @@ -23,6 +25,8 @@ * tile.accent (string, optional) : accentuation du composant +* tile.icon (boolean, optional) : Si false, ajoute la classe fr-tile--no-icon pour désactiver l'icone associée au lien + * tile.classes (array, optional) : Classes suplémentaires sur la tuile %> @@ -43,17 +47,29 @@ switch (tile.size) { break; } -if (tile.enlarge) classes.push(`${prefix}-enlarge-link`); -if (tile.horizontal !== undefined) { - classes.push(`${prefix}-tile--horizontal`); -} -if (tile.horizontalMd !== undefined) { - classes.push(`${prefix}-tile--horizontal-md`); +switch (tile.horizontal) { + case true: + classes.push(`${prefix}-tile--horizontal`); + break; } -if (tile.verticalMd !== undefined) { - classes.push(`${prefix}-tile--vertical-md`); + +switch (tile.vertical) { + case true: + classes.push(`${prefix}-tile--vertical`); + break; + + case 'md': + classes.push(`${prefix}-tile--vertical@md`); + break; + + case 'lg': + classes.push(`${prefix}-tile--vertical@lg`); + break; } +if (tile.download) classes.push(`${prefix}-tile--download`); +if (tile.icon === false) classes.push(`${prefix}-tile--no-icon`); +if (tile.enlarge) classes.push(`${prefix}-enlarge-link`); if (tile.accent !== undefined) classes.push(`${prefix}-tile--${tile.accent}`); %> From 68d562cb105bf0bbe3ac5de1139c7afc306a9343 Mon Sep 17 00:00:00 2001 From: Keryan SANIE Date: Fri, 16 Jun 2023 12:38:26 +0200 Subject: [PATCH 04/32] =?UTF-8?q?=E2=9C=A8=20feat(name):=20ajout=20bouton?= =?UTF-8?q?=20de=20suppression=20de=20pr=C3=A9nom=20[DS-2974]=20(#493)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dans le modèle de de bloc nom/prénom, un bouton permet d'ajouter des champs de saisie pour les prénoms secondaires -> ajout d'un bouton permettant de supprimer ces champs ajoutés --- src/component/follow/style/_module.scss | 9 ++++ .../input/input-base/example/index.ejs | 2 + .../example/sample/input-action.ejs | 6 +++ src/component/input/input-base/i18n/fr.yml | 4 +- .../input/input-base/style/_module.scss | 48 ++++++++----------- .../input/input-base/style/_scheme.scss | 2 +- .../input/input-base/template/ejs/input.ejs | 36 +++++++------- .../name/example/data/js/add-firstname.js | 26 ++++++++-- .../name/example/data/js/remove-firstname.js | 3 ++ src/pattern/name/i18n/fr.yml | 1 + 10 files changed, 85 insertions(+), 52 deletions(-) create mode 100755 src/component/input/input-base/example/sample/input-action.ejs create mode 100644 src/pattern/name/example/data/js/remove-firstname.js diff --git a/src/component/follow/style/_module.scss b/src/component/follow/style/_module.scss index 88b2398c5..f52f80ef7 100644 --- a/src/component/follow/style/_module.scss +++ b/src/component/follow/style/_module.scss @@ -13,6 +13,11 @@ &__newsletter { #{ns-group(input)} { + @include margin-bottom(4v); + @include margin-bottom(2v, sm); + } + + #{ns(hint-text)} { @include margin-bottom(0); } @@ -28,10 +33,14 @@ #{ns(input)} { @include margin-bottom(4v); @include margin-top(0); + border-radius: #{spacing.space(1v)} #{spacing.space(1v)} 0 0; } #{ns(btn)} { justify-content: center; + @include width(100%); + @include width(auto, sm); + border-radius: 0; } @include respond-from(sm) { diff --git a/src/component/input/input-base/example/index.ejs b/src/component/input/input-base/example/index.ejs index cce235595..033b0b25f 100755 --- a/src/component/input/input-base/example/index.ejs +++ b/src/component/input/input-base/example/index.ejs @@ -19,6 +19,8 @@ <%- sample(getText('sample.button', 'input-base'), './sample/input-button.ejs', {input: { id:'text-input-button' }}, true); %> +<%- sample(getText('sample.action', 'input-base'), './sample/input-action.ejs', {input: { id:'text-input-action' }}, true); %> + <%- sample(getText('sample.placeholder', 'input-base'), './sample/input-text.ejs', {input: { id:'text-input-placeholder', placeholder:'placeholder'}}, true); %> <%- sample(getText('sample.value', 'input-base'), './sample/input-text.ejs', {input: { id:'text-input-value', attributes: {value:'value'}}}, true); %> diff --git a/src/component/input/input-base/example/sample/input-action.ejs b/src/component/input/input-base/example/sample/input-action.ejs new file mode 100755 index 000000000..7859d0e01 --- /dev/null +++ b/src/component/input/input-base/example/sample/input-action.ejs @@ -0,0 +1,6 @@ +<% +const input = locals.input || {} +input.action = true; +input.button = input.button || {label: getText('remove-field', 'input-base'), kind: 2, icon: 'delete-line', type: 'button'}; +%> +<%- include('input-text', { input: input }); %> diff --git a/src/component/input/input-base/i18n/fr.yml b/src/component/input/input-base/i18n/fr.yml index 3d8acddb7..47e1e09e5 100644 --- a/src/component/input/input-base/i18n/fr.yml +++ b/src/component/input/input-base/i18n/fr.yml @@ -9,7 +9,8 @@ sample: date: Champs de type "date" textarea: Champs de type "textarea" password: Champs de type "password" - button: Combo champs + bouton + button: Combo champs + bouton d'envoi + action: Combo champs + bouton d'action placeholder: Champs avec placeholder value: Champs avec valeur initiale disabled: Champs désactivé @@ -17,6 +18,7 @@ sample: icon: Champs avec icône personalisée valid: Champs valide avec texte de succès error: Champs en erreur avec texte d'erreur +remove-field: Supprimer le champ subdir: title: Autres versions deprecated: version dépréciée diff --git a/src/component/input/input-base/style/_module.scss b/src/component/input/input-base/style/_module.scss index f2772ce1a..5f04a8672 100644 --- a/src/component/input/input-base/style/_module.scss +++ b/src/component/input/input-base/style/_module.scss @@ -12,9 +12,10 @@ @include text-style(md); @include padding(2v 4v); - /** - * Style du placeholder - */ + &:not(textarea) { + max-height: 2.5rem; + } + @include placeholder { opacity: 1; font-style: italic; @@ -24,13 +25,6 @@ cursor: pointer; } - /** - * On applique une hauteur maximale si l'élément n'est pas un textarea - */ - &:not(textarea) { - max-height: 2.5rem; - } - &[type=date] { min-height: 2.5rem; @@ -50,14 +44,15 @@ } } -/** - * Ajout d'un wrapper quand on a besoin de mettre une icône - */ #{ns(input-wrap)} { @include relative; display: block; @include has-icon { + #{ns(input)} { + @include padding-right(10v); + } + @include icon-size(sm, before) { @include absolute(3v, 3v, 3v); @include margin(auto); @@ -65,31 +60,30 @@ } } - &--addon { + &--addon, + &--action { @include display-flex; @include size(100%); } - #{ns(input)} { - @include padding-right(10v); - } - - > *:first-child:not(:last-child) { - &#{ns(input)} { - @include padding-right(4v); - } - - @include respond-from(md) { + &--addon { + > *:first-child:not(:last-child) { border-radius: spacing.space(1v 0 0 0); } - } - > *:last-child:not(:first-child) { - @include respond-from(md) { + > *:last-child:not(:first-child) { border-radius: spacing.space(0 1v 0 0); } } + &--action #{ns(btn)} { + @include margin-left(4v); + } + + &--action #{ns(btn)} { + @include margin-left(4v); + } + + #{ns(hint-text)} { @include margin-top(4v); } diff --git a/src/component/input/input-base/style/_scheme.scss b/src/component/input/input-base/style/_scheme.scss index 2fb3d1374..f2b8ee88b 100644 --- a/src/component/input/input-base/style/_scheme.scss +++ b/src/component/input/input-base/style/_scheme.scss @@ -50,7 +50,7 @@ } } - #{ns(input-wrap)} { + #{ns(input-wrap--addon)} { > *:not(:last-child) { &#{ns(input)}:not(#{ns(input--valid)}):not(#{ns(input--error)}) { @include color.box-shadow(action-high blue-france, (legacy:$legacy), bottom-2-in); diff --git a/src/component/input/input-base/template/ejs/input.ejs b/src/component/input/input-base/template/ejs/input.ejs index af80002f6..5943e2e4a 100644 --- a/src/component/input/input-base/template/ejs/input.ejs +++ b/src/component/input/input-base/template/ejs/input.ejs @@ -96,34 +96,32 @@ if (input.value) attributes.value = input.value; if (input.autocomplete) attributes.autocomplete = input.autocomplete; attributes.id = input.id; if (input.spellcheck === true || input.spellcheck === false) attributes.spellcheck = `${input.spellcheck}`; + +const inputWrapClass = []; +if (input.button || input.icon) inputWrapClass.push(`${prefix}-input-wrap`); +if (input.icon) inputWrapClass.push(`${prefix}-icon-${input.icon === true ? '' : input.icon}`); +if (input.addon) inputWrapClass.push(`${prefix}-input-wrap--addon`); +if (input.action) inputWrapClass.push(`${prefix}-input-wrap--action`); %> <%- include('../../../../form/template/ejs/label', { label: label }); %> -<% if (input.icon) { %> - <% let icon = prefix + '-icon-' + input.icon; %> - <% if (input.icon === true) icon = ''; - %> -
+<% if (input.icon || input.button) { %> +
> <% } %> -<% if (input.addon && input.button) { %> -
-<% } %> + <% if (input.type === 'textarea') { %> + + <% } + else {%> + <%- includeAttrs(attributes); %> type="<%= inputType %>"> + <% } %> -<% if (input.type === 'textarea') { %> - -<% } -else {%> - <%- includeAttrs(attributes); %> type="<%= inputType %>"> -<% } %> - -<% if (input.addon && input.button) { %> + <% if (input.button) { %> <%- include('../../../../button/template/ejs/button', { button:input.button }); %> -
-<% } %> + <% } %> -<% if (input.icon) { %> +<% if (input.icon || input.button) { %>
<% } %> diff --git a/src/pattern/name/example/data/js/add-firstname.js b/src/pattern/name/example/data/js/add-firstname.js index 3778a6249..d82d6dafb 100644 --- a/src/pattern/name/example/data/js/add-firstname.js +++ b/src/pattern/name/example/data/js/add-firstname.js @@ -8,10 +8,28 @@ const getFieldsetElement = (node) => { }; const firstname = getFieldsetElement(document.getElementById('<%= id %>')); - const reference = getFieldsetElement(this); const copy = firstname.cloneNode(true); -copy.innerHTML = copy.innerHTML.replace(/<%= id %>/g, `<%= id %>-added-${this.firstnamesCount}`).replace('name="given-name"', `name="additional-name-${this.firstnamesCount}"`).replace('autocomplete="given-name"', 'autocomplete="additional-name"'); -const container = reference.parentNode; -container.insertBefore(copy, reference); +let html = copy.innerHTML; +html = html.replace(/<%= id %>/g, `<%= id %>-added-${this.firstnamesCount}`); +html = html.replace('name="given-name"', `name="additional-name-${this.firstnamesCount}"`); +html = html.replace('autocomplete="given-name"', 'autocomplete="additional-name"'); +copy.innerHTML = html; + +const wrapper = document.createElement('div'); +wrapper.classList = '<%= prefix %>-input-wrap <%= prefix %>-input-wrap--action'; + +const removeButton = document.createElement('button'); +const labelRemoveButton = '<%= getText("label.remove-firstname", "name") %>'; +removeButton.classList = '<%= prefix %>-btn <%= prefix %>-btn--tertiary <%= prefix %>-icon-delete-line'; +removeButton.innerHTML = labelRemoveButton; +removeButton.title = labelRemoveButton; + +removeButton.setAttribute('onclick', `<%- include('remove-firstname.js') %>`); + +wrapper.appendChild(copy.getElementsByTagName('input')[0]); +wrapper.appendChild(removeButton); +copy.getElementsByTagName('label')[0].after(wrapper); +reference.parentNode.insertBefore(copy, reference); +document.getElementById(`<%= id %>-added-${this.firstnamesCount}`).focus(); diff --git a/src/pattern/name/example/data/js/remove-firstname.js b/src/pattern/name/example/data/js/remove-firstname.js new file mode 100644 index 000000000..b4bf17aa7 --- /dev/null +++ b/src/pattern/name/example/data/js/remove-firstname.js @@ -0,0 +1,3 @@ +const input = document.getElementById('<%= id %>-added-${this.firstnamesCount}'); +input.closest('.<%= prefix %>-fieldset__element').remove(); +this.closest('.<%= prefix %>-fieldset__element').remove(); diff --git a/src/pattern/name/i18n/fr.yml b/src/pattern/name/i18n/fr.yml index 931c467f1..740077983 100644 --- a/src/pattern/name/i18n/fr.yml +++ b/src/pattern/name/i18n/fr.yml @@ -7,6 +7,7 @@ hint: birth: Nom de famille non rectifié après décision du tribunal label: add-firstname: Ajouter un prénom + remove-firstname: Supprimer le prénom country: Pays family: Nom given: Prénom From 070e81631694b646019fa91ff3014da1856dd2f7 Mon Sep 17 00:00:00 2001 From: lab9 Date: Fri, 16 Jun 2023 12:42:22 +0200 Subject: [PATCH 05/32] =?UTF-8?q?=F0=9F=90=9B=20fix(tab):=20=C3=A9coute=20?= =?UTF-8?q?des=20=C3=A9v=C3=A9nements=20de=20clavier=20d=C3=A9plac=C3=A9?= =?UTF-8?q?=20sur=20la=20liste=20d'onglets=20[DS-2550]=20(#531)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L'écoute des événements de clavier se faisant sur le composant, il est impossible d'interagir avec des éléments de formulaire dans le contenu de l'onglet -> l'écoute est déplacée au niveau de la liste des onglets, ce qui en exclut le contenu --- src/component/tab/index.js | 4 ++- src/component/tab/script/tab/tab-emission.js | 6 ++++ src/component/tab/script/tab/tab-keys.js | 6 ++++ src/component/tab/script/tab/tabs-group.js | 38 ++++++++++++++------ src/component/tab/script/tab/tabs-list.js | 33 +++++++++-------- src/component/tab/style/module/_shadow.scss | 28 +++++++-------- 6 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 src/component/tab/script/tab/tab-emission.js create mode 100644 src/component/tab/script/tab/tab-keys.js diff --git a/src/component/tab/index.js b/src/component/tab/index.js index e6caca659..4cbfe9fdd 100644 --- a/src/component/tab/index.js +++ b/src/component/tab/index.js @@ -4,13 +4,15 @@ import { TabButton } from './script/tab/tab-button.js'; import { TabsGroup } from './script/tab/tabs-group.js'; import { TabsList } from './script/tab/tabs-list.js'; import { TabSelector } from './script/tab/tab-selector.js'; +import { TabEmission } from './script/tab/tab-emission.js'; api.tab = { TabPanel: TabPanel, TabButton: TabButton, TabsGroup: TabsGroup, TabsList: TabsList, - TabSelector: TabSelector + TabSelector: TabSelector, + TabEmission: TabEmission }; export default api; diff --git a/src/component/tab/script/tab/tab-emission.js b/src/component/tab/script/tab/tab-emission.js new file mode 100644 index 000000000..c818beb2f --- /dev/null +++ b/src/component/tab/script/tab/tab-emission.js @@ -0,0 +1,6 @@ +import api from '../../api.js'; + +export const TabEmission = { + PRESS_KEY: api.internals.ns.emission('tab', 'press_key'), + LIST_HEIGHT: api.internals.ns.emission('tab', 'list_height') +}; diff --git a/src/component/tab/script/tab/tab-keys.js b/src/component/tab/script/tab/tab-keys.js new file mode 100644 index 000000000..b19d57b5a --- /dev/null +++ b/src/component/tab/script/tab/tab-keys.js @@ -0,0 +1,6 @@ +export const TabKeys = { + LEFT: 'tab_keys_left', + RIGHT: 'tab_keys_right', + HOME: 'tab_keys_home', + END: 'tab_keys_end' +}; diff --git a/src/component/tab/script/tab/tabs-group.js b/src/component/tab/script/tab/tabs-group.js index e3e6bd7ec..011453ef8 100644 --- a/src/component/tab/script/tab/tabs-group.js +++ b/src/component/tab/script/tab/tabs-group.js @@ -1,5 +1,7 @@ import api from '../../api.js'; import { TabPanelDirection } from './tab-panel-direction.js'; +import { TabKeys } from './tab-keys'; +import { TabEmission } from './tab-emission'; /** * TabGroup est la classe étendue de DiscosuresGroup @@ -17,17 +19,13 @@ class TabsGroup extends api.core.DisclosuresGroup { init () { super.init(); this.listen('transitionend', this.transitionend.bind(this)); - this.listenKey(api.core.KeyCodes.RIGHT, this.pressRight.bind(this), true, true); - this.listenKey(api.core.KeyCodes.LEFT, this.pressLeft.bind(this), true, true); - this.listenKey(api.core.KeyCodes.HOME, this.pressHome.bind(this), true, true); - this.listenKey(api.core.KeyCodes.END, this.pressEnd.bind(this), true, true); + this.addAscent(TabEmission.PRESS_KEY, this.pressKey.bind(this)); + this.addAscent(TabEmission.LIST_HEIGHT, this.setListHeight.bind(this)); this.isRendering = true; - - if (this.list) this.list.apply(); } - get list () { - return this.element.getDescendantInstances('TabsList', 'TabsGroup', true)[0]; + setListHeight (value) { + this.listHeight = value; } transitionend (e) { @@ -38,6 +36,26 @@ class TabsGroup extends api.core.DisclosuresGroup { return this.members.some(member => member.buttonHasFocus); } + pressKey (key) { + switch (key) { + case TabKeys.LEFT: + this.pressLeft(); + break; + + case TabKeys.RIGHT: + this.pressRight(); + break; + + case TabKeys.HOME: + this.pressHome(); + break; + + case TabKeys.END: + this.pressEnd(); + break; + } + } + /** * Selectionne l'element suivant de la liste si on est sur un bouton * Si on est à la fin on retourne au début @@ -119,9 +137,7 @@ class TabsGroup extends api.core.DisclosuresGroup { const paneHeight = Math.round(this.current.node.offsetHeight); if (this.panelHeight === paneHeight) return; this.panelHeight = paneHeight; - let listHeight = 0; - if (this.list) listHeight = this.list.node.offsetHeight; - this.style.setProperty('--tabs-height', (this.panelHeight + listHeight) + 'px'); + this.style.setProperty('--tabs-height', (this.panelHeight + this.listHeight) + 'px'); } } diff --git a/src/component/tab/script/tab/tabs-list.js b/src/component/tab/script/tab/tabs-list.js index 165437337..ce9cadfbe 100644 --- a/src/component/tab/script/tab/tabs-list.js +++ b/src/component/tab/script/tab/tabs-list.js @@ -1,5 +1,8 @@ import api from '../../api.js'; import { TabSelector } from './tab-selector'; +import { TabKeys } from './tab-keys'; +import { TabEmission } from './tab-emission'; +import { TableEmission } from '../../../table/script/table/table-emission'; const FOCALIZE_OFFSET = 16; const SCROLL_OFFSET = 16; // valeur en px du scroll avant laquelle le shadow s'active ou se desactive @@ -11,13 +14,13 @@ class TabsList extends api.core.Instance { init () { this.listen('scroll', this.scroll.bind(this)); + this.listenKey(api.core.KeyCodes.RIGHT, this.ascend.bind(this, TabEmission.PRESS_KEY, TabKeys.RIGHT), true, true); + this.listenKey(api.core.KeyCodes.LEFT, this.ascend.bind(this, TabEmission.PRESS_KEY, TabKeys.LEFT), true, true); + this.listenKey(api.core.KeyCodes.HOME, this.ascend.bind(this, TabEmission.PRESS_KEY, TabKeys.HOME), true, true); + this.listenKey(api.core.KeyCodes.END, this.ascend.bind(this, TabEmission.PRESS_KEY, TabKeys.END), true, true); this.isResizing = true; } - get group () { - return this.element.getAscendantInstance('TabsGroup', 'TabsList'); - } - focalize (btn) { const btnRect = btn.getRect(); const listRect = this.getRect(); @@ -37,20 +40,18 @@ class TabsList extends api.core.Instance { } apply () { - if (!this.group) return; if (this._isScrolling) { - this.group.addClass(TabSelector.SHADOW); + this.addClass(TabSelector.SHADOW); this.scroll(); } else { - this.group.removeClass(TabSelector.SHADOW_RIGHT); - this.group.removeClass(TabSelector.SHADOW_LEFT); - this.group.removeClass(TabSelector.SHADOW); + this.removeClass(TabSelector.SHADOW_RIGHT); + this.removeClass(TabSelector.SHADOW_LEFT); + this.removeClass(TabSelector.SHADOW); } } /* ajoute la classe fr-table__shadow-left ou fr-table__shadow-right sur fr-table en fonction d'une valeur de scroll et du sens (right, left) */ scroll () { - if (!this.group) return; const scrollLeft = this.node.scrollLeft; const isMin = scrollLeft <= SCROLL_OFFSET; const max = this.node.scrollWidth - this.node.clientWidth - SCROLL_OFFSET; @@ -61,21 +62,23 @@ class TabsList extends api.core.Instance { const maxSelector = isRtl ? TabSelector.SHADOW_LEFT : TabSelector.SHADOW_RIGHT; if (isMin) { - this.group.removeClass(minSelector); + this.removeClass(minSelector); } else { - this.group.addClass(minSelector); + this.addClass(minSelector); } if (isMax) { - this.group.removeClass(maxSelector); + this.removeClass(maxSelector); } else { - this.group.addClass(maxSelector); + this.addClass(maxSelector); } } resize () { this.isScrolling = this.node.scrollWidth > this.node.clientWidth + SCROLL_OFFSET; - this.setProperty('--tab-list-height', `${this.getRect().height}px`); + const height = this.getRect().height; + this.setProperty('--tabs-list-height', `${height}px`); + this.ascend(TabEmission.LIST_HEIGHT, height); } dispose () { diff --git a/src/component/tab/style/module/_shadow.scss b/src/component/tab/style/module/_shadow.scss index c473dfab4..8aa611324 100644 --- a/src/component/tab/style/module/_shadow.scss +++ b/src/component/tab/style/module/_shadow.scss @@ -9,24 +9,22 @@ * Ombres ajoutées en Js si le contenu est plus grand que le conteneur */ #{ns(tabs__shadow)} { - --tab-list-height: #{space(12v)}; + --tabs-list-height: #{space(12v)}; - & > #{ns(tabs__list)} { - @include before('', block) { - @include absolute(4px, 0, null, 0); - @include z-index(above); - @include _tabs-scroll-shadow(false, false); - @include height(calc(var(--tab-list-height) - 8px)); - opacity: 0.8; - pointer-events: none; - transition: box-shadow 0.3s; - } + @include before('', block) { + @include absolute(4px, 0, null, 0); + @include z-index(above); + @include _tabs-scroll-shadow(false, false); + @include height(calc(var(--tabs-list-height) - 8px)); + opacity: 0.8; + pointer-events: none; + transition: box-shadow 0.3s; } /** * Modifier ombre à gauche **/ - &--left > #{ns(tabs__list)} { + &--left { @include before { @include _tabs-scroll-shadow(true, false); // @TODO: à implementer dans la mixin shadow } @@ -35,7 +33,7 @@ /** * Modifier ombre à droite **/ - &--right > #{ns(tabs__list)} { + &--right { @include before { @include _tabs-scroll-shadow(false, true); // @TODO: à implementer dans la mixin shadow } @@ -44,7 +42,7 @@ /** * Modifier combinaison ombre à gauche et ombre à droite **/ - &--left#{&}--right > #{ns(tabs__list)} { + &--left#{&}--right { @include before { @include _tabs-scroll-shadow(true, true); // @TODO: à implementer dans la mixin shadow } @@ -52,7 +50,7 @@ } @include selector.theme(dark) { - #{ns(tabs__shadow)} > #{ns(tabs__list)} { + #{ns(tabs__shadow)} { @include before { opacity: 1; } From 6cda28560e0858dce154ef01b718c0af60ab1b8b Mon Sep 17 00:00:00 2001 From: lab9 Date: Fri, 16 Jun 2023 15:34:49 +0200 Subject: [PATCH 06/32] =?UTF-8?q?=E2=9C=A8=20feat(core):=20ouverture=20des?= =?UTF-8?q?=20disclosures=20=C3=A0=20partir=20des=20ancres,=20=C3=A9tat=20?= =?UTF-8?q?disabled=20d=C3=A9sactive=20disclosure=20[DS-2805,=20DS-2533]?= =?UTF-8?q?=20(#532)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Correctif de l'état disabled sur les boutons associés à une modale, un onglet ou un accordéon. La fonctionnalité d'ouverture est désactivée si les boutons primaires sont désactivés. - Ajout de la fonctionnalité d'ouverture d'une modale, d'un onglet ou d'un accordéon si la partie ancre de l'url correspond à l'id de l'élément -> les liens d'évitements peuvent ouvrir le menu et la recherche en mobile. --- .../component/accordion/integrate.js | 10 + .../integration/component/alert/integrate.js | 9 + .../integration/component/badge/integrate.js | 9 + .../component/breadcrumb/integrate.js | 13 + .../integration/component/button/integrate.js | 9 + .../component/callout/integrate.js | 9 + .../integration/component/card/integrate.js | 9 + .../component/checkbox/integrate.js | 9 + .../integration/component/components.js | 264 +++++------------- .../component/connect/integrate.js | 11 + .../component/consent/integrate.js | 9 + .../component/content/integrate.js | 9 + .../component/download/integrate.js | 9 + .../integration/component/follow/integrate.js | 9 + .../integration/component/footer/integrate.js | 11 + .../integration/component/header/integrate.js | 17 ++ .../component/highlight/integrate.js | 9 + .../integration/component/input/integrate.js | 9 + .../integration/component/link/integrate.js | 9 + .../integration/component/modal/integrate.js | 10 + .../component/navigation/integrate.js | 15 + .../integration/component/notice/integrate.js | 9 + .../component/pagination/integrate.js | 11 + .../integration/component/quote/integrate.js | 9 + .../integration/component/radio/integrate.js | 9 + .../integration/component/search/integrate.js | 9 + .../integration/component/select/integrate.js | 9 + .../integration/component/share/integrate.js | 9 + .../component/sidemenu/integrate.js | 15 + .../component/stepper/integrate.js | 9 + .../component/summary/integrate.js | 13 + .../integration/component/tab/integrate.js | 10 + .../integration/component/table/integrate.js | 9 + .../integration/component/tag/integrate.js | 9 + .../integration/component/tile/integrate.js | 9 + .../integration/component/toggle/integrate.js | 9 + .../component/transcription/integrate.js | 9 + .../transcription/transcription-selector.js | 9 +- .../component/translate/integrate.js | 9 + .../component/translate/translate-selector.js | 6 +- .../integration/component/upload/integrate.js | 9 + src/component/accordion/index.js | 2 + src/component/accordion/main.js | 1 + .../script/accordion/accordion-selector.js | 7 +- .../accordion/script/accordion/accordion.js | 15 + .../script/accordion/accordions-group.js | 2 +- .../script/breadcrumb/breadcrumb-selector.js | 3 +- .../script/breadcrumb/breadcrumb.js | 6 + .../header/example/sample/header.ejs | 9 +- .../header/script/header/header-modal.js | 13 +- src/component/header/template/ejs/tools.ejs | 2 +- src/component/main.js | 1 + src/component/modal/script/modal/modal.js | 8 +- .../script/navigation/navigation-item.js | 5 + .../script/navigation/navigation-selector.js | 13 +- .../script/navigation/navigation.js | 6 +- .../navigation/style/scheme/_default.scss | 2 +- .../script/password/password-toggle.js | 4 +- .../sidemenu/example/sample/sidemenu.ejs | 1 + src/component/sidemenu/index.js | 2 + src/component/sidemenu/main.js | 1 + .../sidemenu/script/sidemenu/sidemenu-item.js | 15 + .../sidemenu/script/sidemenu/sidemenu-list.js | 2 +- .../script/sidemenu/sidemenu-selector.js | 7 +- .../sidemenu/template/ejs/sidemenu.ejs | 4 +- src/component/skiplink/example/prepend.ejs | 2 +- src/component/tab/script/tab/tab-button.js | 6 + src/component/tab/script/tab/tab-panel.js | 6 + src/component/tab/script/tab/tabs-group.js | 11 + src/component/tab/style/_scheme.scss | 5 +- .../tag/script/tag/tag-dismissible.js | 4 +- src/component/transcription/api.js | 2 + src/component/transcription/index.js | 10 + src/component/transcription/main.js | 5 + .../accordion/transcription-selector.js | 8 + .../script/accordion/transcription.js | 15 + src/core/script/action/toggle/toggle.js | 4 +- src/core/script/api/engine.js | 2 + src/core/script/api/modules/hash/hash.js | 43 +++ .../script/api/modules/register/instance.js | 84 ++++++ .../api/modules/scroll/scroll-locker.js | 17 +- src/core/script/collapse/collapse.js | 24 +- .../script/disclosure/disclosure-button.js | 60 +++- .../script/disclosure/disclosure-emission.js | 4 +- src/core/script/disclosure/disclosure-type.js | 9 +- src/core/script/disclosure/disclosure.js | 132 +++++++-- .../script/disclosure/disclosures-group.js | 57 +++- src/core/style/display/module/_no-scroll.scss | 2 - 88 files changed, 1019 insertions(+), 282 deletions(-) create mode 100644 src/analytics/script/integration/component/accordion/integrate.js create mode 100644 src/analytics/script/integration/component/alert/integrate.js create mode 100644 src/analytics/script/integration/component/badge/integrate.js create mode 100644 src/analytics/script/integration/component/breadcrumb/integrate.js create mode 100644 src/analytics/script/integration/component/button/integrate.js create mode 100644 src/analytics/script/integration/component/callout/integrate.js create mode 100644 src/analytics/script/integration/component/card/integrate.js create mode 100644 src/analytics/script/integration/component/checkbox/integrate.js create mode 100644 src/analytics/script/integration/component/connect/integrate.js create mode 100644 src/analytics/script/integration/component/consent/integrate.js create mode 100644 src/analytics/script/integration/component/content/integrate.js create mode 100644 src/analytics/script/integration/component/download/integrate.js create mode 100644 src/analytics/script/integration/component/follow/integrate.js create mode 100644 src/analytics/script/integration/component/footer/integrate.js create mode 100644 src/analytics/script/integration/component/header/integrate.js create mode 100644 src/analytics/script/integration/component/highlight/integrate.js create mode 100644 src/analytics/script/integration/component/input/integrate.js create mode 100644 src/analytics/script/integration/component/link/integrate.js create mode 100644 src/analytics/script/integration/component/modal/integrate.js create mode 100644 src/analytics/script/integration/component/navigation/integrate.js create mode 100644 src/analytics/script/integration/component/notice/integrate.js create mode 100644 src/analytics/script/integration/component/pagination/integrate.js create mode 100644 src/analytics/script/integration/component/quote/integrate.js create mode 100644 src/analytics/script/integration/component/radio/integrate.js create mode 100644 src/analytics/script/integration/component/search/integrate.js create mode 100644 src/analytics/script/integration/component/select/integrate.js create mode 100644 src/analytics/script/integration/component/share/integrate.js create mode 100644 src/analytics/script/integration/component/sidemenu/integrate.js create mode 100644 src/analytics/script/integration/component/stepper/integrate.js create mode 100644 src/analytics/script/integration/component/summary/integrate.js create mode 100644 src/analytics/script/integration/component/tab/integrate.js create mode 100644 src/analytics/script/integration/component/table/integrate.js create mode 100644 src/analytics/script/integration/component/tag/integrate.js create mode 100644 src/analytics/script/integration/component/tile/integrate.js create mode 100644 src/analytics/script/integration/component/toggle/integrate.js create mode 100644 src/analytics/script/integration/component/transcription/integrate.js create mode 100644 src/analytics/script/integration/component/translate/integrate.js create mode 100644 src/analytics/script/integration/component/upload/integrate.js create mode 100644 src/component/accordion/script/accordion/accordion.js create mode 100644 src/component/sidemenu/script/sidemenu/sidemenu-item.js create mode 100644 src/component/transcription/api.js create mode 100644 src/component/transcription/index.js create mode 100644 src/component/transcription/main.js create mode 100644 src/component/transcription/script/accordion/transcription-selector.js create mode 100644 src/component/transcription/script/accordion/transcription.js create mode 100644 src/core/script/api/modules/hash/hash.js diff --git a/src/analytics/script/integration/component/accordion/integrate.js b/src/analytics/script/integration/component/accordion/integrate.js new file mode 100644 index 000000000..feecb5c38 --- /dev/null +++ b/src/analytics/script/integration/component/accordion/integrate.js @@ -0,0 +1,10 @@ +import api from '../../../../api'; +import { AccordionActionee } from './accordion-actionee'; + +const integrateAccordion = () => { + if (api.accordion) { + api.internals.register(api.accordion.AccordionSelector.COLLAPSE, AccordionActionee); + } +}; + +export default integrateAccordion; diff --git a/src/analytics/script/integration/component/alert/integrate.js b/src/analytics/script/integration/component/alert/integrate.js new file mode 100644 index 000000000..a9a632074 --- /dev/null +++ b/src/analytics/script/integration/component/alert/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { AlertSelector } from './alert-selector'; +import { AlertActionee } from './alert-actionee'; + +const integrateAlert = () => { + api.internals.register(AlertSelector.ALERT, AlertActionee); +}; + +export default integrateAlert; diff --git a/src/analytics/script/integration/component/badge/integrate.js b/src/analytics/script/integration/component/badge/integrate.js new file mode 100644 index 000000000..022f60714 --- /dev/null +++ b/src/analytics/script/integration/component/badge/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { BadgeSelector } from './badge-selector'; +import { BadgeActionee } from './badge-actionee'; + +const integrateBadge = () => { + api.internals.register(BadgeSelector.BADGE, BadgeActionee); +}; + +export default integrateBadge; diff --git a/src/analytics/script/integration/component/breadcrumb/integrate.js b/src/analytics/script/integration/component/breadcrumb/integrate.js new file mode 100644 index 000000000..56430058d --- /dev/null +++ b/src/analytics/script/integration/component/breadcrumb/integrate.js @@ -0,0 +1,13 @@ +import api from '../../../../api'; +import { BreadcrumbSelector } from './breadcrumb-selector'; +import { BreadcrumbActionee } from './breadcrumb-actionee'; +import { BreadcrumbLinkActionee } from './breadcrumb-link-actionee'; + +const integrateBreadcrumb = () => { + if (api.breadcrumb) { + api.internals.register(BreadcrumbSelector.COLLAPSE, BreadcrumbActionee); + api.internals.register(BreadcrumbSelector.LINK, BreadcrumbLinkActionee); + } +}; + +export default integrateBreadcrumb; diff --git a/src/analytics/script/integration/component/button/integrate.js b/src/analytics/script/integration/component/button/integrate.js new file mode 100644 index 000000000..f05da1806 --- /dev/null +++ b/src/analytics/script/integration/component/button/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { ButtonSelector } from './button-selector'; +import { ButtonActionee } from './button-actionee'; + +const integrateButton = () => { + api.internals.register(ButtonSelector.BUTTON, ButtonActionee); +}; + +export default integrateButton; diff --git a/src/analytics/script/integration/component/callout/integrate.js b/src/analytics/script/integration/component/callout/integrate.js new file mode 100644 index 000000000..685c2ecc3 --- /dev/null +++ b/src/analytics/script/integration/component/callout/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { CalloutSelector } from './callout-selector'; +import { CalloutActionee } from './callout-actionee'; + +const integrateCallout = () => { + api.internals.register(CalloutSelector.CALLOUT, CalloutActionee); +}; + +export default integrateCallout; diff --git a/src/analytics/script/integration/component/card/integrate.js b/src/analytics/script/integration/component/card/integrate.js new file mode 100644 index 000000000..847b77f9a --- /dev/null +++ b/src/analytics/script/integration/component/card/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { CardSelector } from './card-selector'; +import { CardActionee } from './card-actionee'; + +const integrateCard = () => { + api.internals.register(CardSelector.CARD, CardActionee); +}; + +export default integrateCard; diff --git a/src/analytics/script/integration/component/checkbox/integrate.js b/src/analytics/script/integration/component/checkbox/integrate.js new file mode 100644 index 000000000..6051902e7 --- /dev/null +++ b/src/analytics/script/integration/component/checkbox/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { CheckboxSelector } from './checkbox-selector'; +import { CheckboxActionee } from './checkbox-actionee'; + +const integrateCheckbox = () => { + api.internals.register(CheckboxSelector.INPUT, CheckboxActionee); +}; + +export default integrateCheckbox; diff --git a/src/analytics/script/integration/component/components.js b/src/analytics/script/integration/component/components.js index 716b467d4..0b7b31a43 100644 --- a/src/analytics/script/integration/component/components.js +++ b/src/analytics/script/integration/component/components.js @@ -1,194 +1,82 @@ import api from '../../../api'; -import { AccordionActionee } from './accordion/accordion-actionee'; -import { BreadcrumbSelector } from './breadcrumb/breadcrumb-selector'; -import { BreadcrumbActionee } from './breadcrumb/breadcrumb-actionee'; -import { BreadcrumbLinkActionee } from './breadcrumb/breadcrumb-link-actionee'; -import { ButtonSelector } from './button/button-selector'; -import { ButtonActionee } from './button/button-actionee'; -import { AlertSelector } from './alert/alert-selector'; -import { AlertActionee } from './alert/alert-actionee'; -import { BadgeSelector } from './badge/badge-selector'; -import { BadgeActionee } from './badge/badge-actionee'; -import { CalloutSelector } from './callout/callout-selector'; -import { CalloutActionee } from './callout/callout-actionee'; -import { ConnectSelector } from './connect/connect-selector'; -import { ConnectActionee } from './connect/connect-actionee'; -import { ConnectLinkActionee } from './connect/connect-link-actionee'; -import { ContentSelector } from './content/content-selector'; -import { ContentActionee } from './content/content-actionee'; -import { ConsentSelector } from './consent/consent-selector'; -import { ConsentActionee } from './consent/consent-actionee'; -import { CardSelector } from './card/card-selector'; -import { CardActionee } from './card/card-actionee'; -import { CheckboxSelector } from './checkbox/checkbox-selector'; -import { CheckboxActionee } from './checkbox/checkbox-actionee'; -import { DownloadSelector } from './download/download-selector'; -import { DownloadActionee } from './download/download-actionee'; -import { FooterSelector } from './footer/footer-selector'; -import { FooterActionee } from './footer/footer-actionee'; -import { FollowSelector } from './follow/follow-selector'; -import { FollowActionee } from './follow/follow-actionee'; -import { FooterLinkActionee } from './footer/footer-link-actionee'; -import { HeaderActionee } from './header/header-actionee'; -import { HeaderSelector } from './header/header-selector'; -import { HeaderModalActionee } from './header/header-modal-actionee'; -import { HeaderToolsButtonActionee } from './header/header-tools-button-actionee'; -import { HeaderMenuButtonActionee } from './header/header-menu-button-actionee'; -import { HighlightSelector } from './highlight/highlight-selector'; -import { HighlightActionee } from './highlight/highlight-actionee'; -import { InputSelector } from './input/input-selector'; -import { InputActionee } from './input/input-actionee'; -import { LinkSelector } from './link/link-selector'; -import { LinkActionee } from './link/link-actionee'; -import { ModalActionee } from './modal/modal-actionee'; -import { NavigationSelector } from './navigation/navigation-selector'; -import { NavigationActionee } from './navigation/navigation-actionee'; -import { NavigationSectionActionee } from './navigation/navigation-section-actionee'; -import { NavigationLinkActionee } from './navigation/navigation-link-actionee'; -import { NoticeSelector } from './notice/notice-selector'; -import { NoticeActionee } from './notice/notice-actionee'; -import { PaginationSelector } from './pagination/pagination-selector'; -import { PaginationActionee } from './pagination/pagination-actionee'; -import { PaginationLinkActionee } from './pagination/pagination-link-actionee'; -import { RadioSelector } from './radio/radio-selector'; -import { RadioActionee } from './radio/radio-actionee'; -import { QuoteSelector } from './quote/quote-selector'; -import { QuoteActionee } from './quote/quote-actionee'; -import { SearchSelector } from './search/search-selector'; -import { SearchActionee } from './search/search-actionee'; -import { SelectSelector } from './select/select-selector'; -import { SelectActionee } from './select/select-actionee'; -import { SidemenuSelector } from './sidemenu/sidemenu-selector'; -import { SidemenuActionee } from './sidemenu/sidemenu-actionee'; -import { SidemenuLinkActionee } from './sidemenu/sidemenu-link-actionee'; -import { SidemenuSectionActionee } from './sidemenu/sidemenu-section-actionee'; -import { ShareSelector } from './share/share-selector'; -import { ShareActionee } from './share/share-actionee'; -import { StepperSelector } from './stepper/stepper-selector'; -import { StepperActionee } from './stepper/stepper-actionee'; -import { SummarySelector } from './summary/summary-selector'; -import { SummaryActionee } from './summary/summary-actionee'; -import { SummaryLinkActionee } from './summary/summary-link-actionee'; -import { SummarySectionActionee } from './summary/summary-section-actionee'; -import { TabActionee } from './tab/tab-actionee'; -import { TableSelector } from './table/table-selector'; -import { TableActionee } from './table/table-actionee'; -import { TileSelector } from './tile/tile-selector'; -import { TileActionee } from './tile/tile-actionee'; -import { ToggleSelector } from './toggle/toggle-selector'; -import { ToggleActionee } from './toggle/toggle-actionee'; -import { TagSelector } from './tag/tag-selector'; -import { TagActionee } from './tag/tag-actionee'; -import { TranscriptionSelector } from './transcription/transcription-selector'; -import { TranscriptionActionee } from './transcription/transcription-actionee'; -import { TranslateSelector } from './translate/translate-selector'; -import { TranslateActionee } from './translate/translate-actionee'; -import { UploadSelector } from './upload/upload-selector'; -import { UploadActionee } from './upload/upload-actionee'; +import integrateAccordion from './accordion/integrate'; +import integrateAlert from './alert/integrate'; +import integrateBreadcrumb from './breadcrumb/integrate'; +import integrateBadge from './badge/integrate'; +import integrateButton from './button/integrate'; +import integrateCallout from './callout/integrate'; +import integrateCard from './card/integrate'; +import integrateCheckbox from './checkbox/integrate'; +import integrateConnect from './connect/integrate'; +import integrateConsent from './consent/integrate'; +import integrateContent from './content/integrate'; +import integrateDownload from './download/integrate'; +import integrateFollow from './follow/integrate'; +import integrateFooter from './footer/integrate'; +import integrateHeader from './header/integrate'; +import integrateHighlight from './highlight/integrate'; +import integrateLink from './link/integrate'; +import integrateInput from './input/integrate'; +import integrateModal from './modal/integrate'; +import integrateNavigation from './navigation/integrate'; +import integrateNotice from './notice/integrate'; +import integratePagination from './pagination/integrate'; +import integrateQuote from './quote/integrate'; +import integrateRadio from './radio/integrate'; +import integrateSearch from './search/integrate'; +import integrateSelect from './select/integrate'; +import integrateShare from './share/integrate'; +import integrateSidemenu from './sidemenu/integrate'; +import integrateStepper from './stepper/integrate'; +import integrateSummary from './summary/integrate'; +import integrateTab from './tab/integrate'; +import integrateTable from './table/integrate'; +import integrateTag from './tag/integrate'; +import integrateTile from './tile/integrate'; +import integrateToggle from './toggle/integrate'; +import integrateTranscription from './transcription/integrate'; +import integrateTranslate from './translate/integrate'; +import integrateUpload from './upload/integrate'; const integrateComponents = () => { - if (api.accordion) { - api.internals.register(api.accordion.AccordionSelector.COLLAPSE, AccordionActionee); - } - - if (api.breadcrumb) { - api.internals.register(BreadcrumbSelector.COLLAPSE, BreadcrumbActionee); - api.internals.register(BreadcrumbSelector.LINK, BreadcrumbLinkActionee); - } - - api.internals.register(AlertSelector.ALERT, AlertActionee); - - api.internals.register(BadgeSelector.BADGE, BadgeActionee); - - api.internals.register(ButtonSelector.BUTTON, ButtonActionee); - - api.internals.register(CalloutSelector.CALLOUT, CalloutActionee); - - api.internals.register(ConnectSelector.CONNECT, ConnectActionee); - api.internals.register(ConnectSelector.LINK, ConnectLinkActionee); - - api.internals.register(ContentSelector.CONTENT, ContentActionee); - - api.internals.register(ConsentSelector.BANNER, ConsentActionee); - - api.internals.register(CardSelector.CARD, CardActionee); - - api.internals.register(InputSelector.INPUT, InputActionee); - - api.internals.register(CheckboxSelector.INPUT, CheckboxActionee); - - api.internals.register(DownloadSelector.LINK, DownloadActionee); - - api.internals.register(FooterSelector.FOOTER, FooterActionee); - api.internals.register(FooterSelector.FOOTER_LINKS, FooterLinkActionee); - - api.internals.register(FollowSelector.FOLLOW, FollowActionee); - - if (api.header) { - api.internals.register(api.header.HeaderSelector.HEADER, HeaderActionee); - api.internals.register(api.header.HeaderSelector.MODALS, HeaderModalActionee); - api.internals.register(HeaderSelector.TOOLS_BUTTON, HeaderToolsButtonActionee); - api.internals.register(HeaderSelector.MENU_BUTTON, HeaderMenuButtonActionee); - } - - api.internals.register(HighlightSelector.HIGHLIGHT, HighlightActionee); - - api.internals.register(LinkSelector.LINK, LinkActionee); - - if (api.modal) { - api.internals.register(api.modal.ModalSelector.MODAL, ModalActionee); - } - - if (api.navigation) { - api.internals.register(api.navigation.NavigationSelector.NAVIGATION, NavigationActionee); - api.internals.register(NavigationSelector.LINK, NavigationLinkActionee); - api.internals.register(api.navigation.NavigationSelector.COLLAPSE, NavigationSectionActionee); - } - - api.internals.register(NoticeSelector.NOTICE, NoticeActionee); - - api.internals.register(PaginationSelector.PAGINATION, PaginationActionee); - api.internals.register(PaginationSelector.LINK, PaginationLinkActionee); - - api.internals.register(QuoteSelector.QUOTE, QuoteActionee); - - api.internals.register(RadioSelector.INPUT, RadioActionee); - - api.internals.register(SearchSelector.SEARCH_BAR, SearchActionee); - - api.internals.register(SelectSelector.SELECT, SelectActionee); - - if (api.sidemenu) { - api.internals.register(SidemenuSelector.SIDEMENU, SidemenuActionee); - api.internals.register(SidemenuSelector.LINK, SidemenuLinkActionee); - api.internals.register(api.sidemenu.SidemenuSelector.COLLAPSE, SidemenuSectionActionee); - } - - api.internals.register(ShareSelector.SHARE, ShareActionee); - - api.internals.register(StepperSelector.STEPPER, StepperActionee); - - api.internals.register(SummarySelector.SUMMARY, SummaryActionee); - api.internals.register(SummarySelector.LINK, SummaryLinkActionee); - api.internals.register(SummarySelector.ITEM, SummarySectionActionee); - - if (api.tab) { - api.internals.register(api.tab.TabSelector.PANEL, TabActionee); - } - - api.internals.register(TableSelector.TABLE, TableActionee); - - api.internals.register(TagSelector.TAG, TagActionee); - - api.internals.register(TileSelector.TILE, TileActionee); - - api.internals.register(ToggleSelector.INPUT, ToggleActionee); - - api.internals.register(TranscriptionSelector.COLLAPSE, TranscriptionActionee); - - api.internals.register(TranslateSelector.COLLAPSE, TranslateActionee); - - api.internals.register(UploadSelector.UPLOAD, UploadActionee); + integrateAccordion(); + integrateBreadcrumb(); + integrateAlert(); + integrateBadge(); + integrateButton(); + integrateCallout(); + integrateConnect(); + integrateConsent(); + integrateContent(); + integrateCard(); + integrateInput(); + integrateCheckbox(); + integrateDownload(); + integrateFooter(); + integrateFollow(); + integrateHeader(); + integrateHighlight(); + integrateLink(); + integrateModal(); + integrateNavigation(); + integrateNotice(); + integratePagination(); + integrateQuote(); + integrateRadio(); + integrateSearch(); + integrateSelect(); + integrateShare(); + integrateSidemenu(); + integrateStepper(); + integrateSummary(); + integrateTab(); + integrateTable(); + integrateTag(); + integrateTile(); + integrateToggle(); + integrateTranscription(); + integrateTranslate(); + integrateUpload(); }; export default integrateComponents; diff --git a/src/analytics/script/integration/component/connect/integrate.js b/src/analytics/script/integration/component/connect/integrate.js new file mode 100644 index 000000000..96923e397 --- /dev/null +++ b/src/analytics/script/integration/component/connect/integrate.js @@ -0,0 +1,11 @@ +import api from '../../../../api'; +import { ConnectSelector } from './connect-selector'; +import { ConnectActionee } from './connect-actionee'; +import { ConnectLinkActionee } from './connect-link-actionee'; + +const integrateConnect = () => { + api.internals.register(ConnectSelector.CONNECT, ConnectActionee); + api.internals.register(ConnectSelector.LINK, ConnectLinkActionee); +}; + +export default integrateConnect; diff --git a/src/analytics/script/integration/component/consent/integrate.js b/src/analytics/script/integration/component/consent/integrate.js new file mode 100644 index 000000000..c998ccc4e --- /dev/null +++ b/src/analytics/script/integration/component/consent/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { ConsentSelector } from './consent-selector'; +import { ConsentActionee } from './consent-actionee'; + +const integrateConsent = () => { + api.internals.register(ConsentSelector.BANNER, ConsentActionee); +}; + +export default integrateConsent; diff --git a/src/analytics/script/integration/component/content/integrate.js b/src/analytics/script/integration/component/content/integrate.js new file mode 100644 index 000000000..b69250748 --- /dev/null +++ b/src/analytics/script/integration/component/content/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { ContentSelector } from './content-selector'; +import { ContentActionee } from './content-actionee'; + +const integrateContent = () => { + api.internals.register(ContentSelector.CONTENT, ContentActionee); +}; + +export default integrateContent; diff --git a/src/analytics/script/integration/component/download/integrate.js b/src/analytics/script/integration/component/download/integrate.js new file mode 100644 index 000000000..52f0162ff --- /dev/null +++ b/src/analytics/script/integration/component/download/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { DownloadSelector } from './download-selector'; +import { DownloadActionee } from './download-actionee'; + +const integrateDownload = () => { + api.internals.register(DownloadSelector.LINK, DownloadActionee); +}; + +export default integrateDownload; diff --git a/src/analytics/script/integration/component/follow/integrate.js b/src/analytics/script/integration/component/follow/integrate.js new file mode 100644 index 000000000..b7fde9bf7 --- /dev/null +++ b/src/analytics/script/integration/component/follow/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { FollowSelector } from './follow-selector'; +import { FollowActionee } from './follow-actionee'; + +const integrateFollow = () => { + api.internals.register(FollowSelector.FOLLOW, FollowActionee); +}; + +export default integrateFollow; diff --git a/src/analytics/script/integration/component/footer/integrate.js b/src/analytics/script/integration/component/footer/integrate.js new file mode 100644 index 000000000..961c82f9d --- /dev/null +++ b/src/analytics/script/integration/component/footer/integrate.js @@ -0,0 +1,11 @@ +import api from '../../../../api'; +import { FooterSelector } from './footer-selector'; +import { FooterActionee } from './footer-actionee'; +import { FooterLinkActionee } from './footer-link-actionee'; + +const integrateFooter = () => { + api.internals.register(FooterSelector.FOOTER, FooterActionee); + api.internals.register(FooterSelector.FOOTER_LINKS, FooterLinkActionee); +}; + +export default integrateFooter; diff --git a/src/analytics/script/integration/component/header/integrate.js b/src/analytics/script/integration/component/header/integrate.js new file mode 100644 index 000000000..8733112b2 --- /dev/null +++ b/src/analytics/script/integration/component/header/integrate.js @@ -0,0 +1,17 @@ +import api from '../../../../api'; +import { HeaderActionee } from './header-actionee'; +import { HeaderModalActionee } from './header-modal-actionee'; +import { HeaderSelector } from './header-selector'; +import { HeaderToolsButtonActionee } from './header-tools-button-actionee'; +import { HeaderMenuButtonActionee } from './header-menu-button-actionee'; + +const integrateHeader = () => { + if (api.header) { + api.internals.register(api.header.HeaderSelector.HEADER, HeaderActionee); + api.internals.register(api.header.HeaderSelector.MODALS, HeaderModalActionee); + api.internals.register(HeaderSelector.TOOLS_BUTTON, HeaderToolsButtonActionee); + api.internals.register(HeaderSelector.MENU_BUTTON, HeaderMenuButtonActionee); + } +}; + +export default integrateHeader; diff --git a/src/analytics/script/integration/component/highlight/integrate.js b/src/analytics/script/integration/component/highlight/integrate.js new file mode 100644 index 000000000..6e5ed68ef --- /dev/null +++ b/src/analytics/script/integration/component/highlight/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { HighlightSelector } from './highlight-selector'; +import { HighlightActionee } from './highlight-actionee'; + +const integrateHighlight = () => { + api.internals.register(HighlightSelector.HIGHLIGHT, HighlightActionee); +}; + +export default integrateHighlight; diff --git a/src/analytics/script/integration/component/input/integrate.js b/src/analytics/script/integration/component/input/integrate.js new file mode 100644 index 000000000..84ef52268 --- /dev/null +++ b/src/analytics/script/integration/component/input/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { InputSelector } from './input-selector'; +import { InputActionee } from './input-actionee'; + +const integrateInput = () => { + api.internals.register(InputSelector.INPUT, InputActionee); +}; + +export default integrateInput; diff --git a/src/analytics/script/integration/component/link/integrate.js b/src/analytics/script/integration/component/link/integrate.js new file mode 100644 index 000000000..1a56e3f3f --- /dev/null +++ b/src/analytics/script/integration/component/link/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { LinkSelector } from './link-selector'; +import { LinkActionee } from './link-actionee'; + +const integrateLink = () => { + api.internals.register(LinkSelector.LINK, LinkActionee); +}; + +export default integrateLink; diff --git a/src/analytics/script/integration/component/modal/integrate.js b/src/analytics/script/integration/component/modal/integrate.js new file mode 100644 index 000000000..b414e661b --- /dev/null +++ b/src/analytics/script/integration/component/modal/integrate.js @@ -0,0 +1,10 @@ +import api from '../../../../api'; +import { ModalActionee } from './modal-actionee'; + +const integrateModal = () => { + if (api.modal) { + api.internals.register(api.modal.ModalSelector.MODAL, ModalActionee); + } +}; + +export default integrateModal; diff --git a/src/analytics/script/integration/component/navigation/integrate.js b/src/analytics/script/integration/component/navigation/integrate.js new file mode 100644 index 000000000..735271c22 --- /dev/null +++ b/src/analytics/script/integration/component/navigation/integrate.js @@ -0,0 +1,15 @@ +import api from '../../../../api'; +import { NavigationActionee } from './navigation-actionee'; +import { NavigationSelector } from './navigation-selector'; +import { NavigationLinkActionee } from './navigation-link-actionee'; +import { NavigationSectionActionee } from './navigation-section-actionee'; + +const integrateNavigation = () => { + if (api.navigation) { + api.internals.register(api.navigation.NavigationSelector.NAVIGATION, NavigationActionee); + api.internals.register(NavigationSelector.LINK, NavigationLinkActionee); + api.internals.register(api.navigation.NavigationSelector.COLLAPSE, NavigationSectionActionee); + } +}; + +export default integrateNavigation; diff --git a/src/analytics/script/integration/component/notice/integrate.js b/src/analytics/script/integration/component/notice/integrate.js new file mode 100644 index 000000000..7c6664d99 --- /dev/null +++ b/src/analytics/script/integration/component/notice/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { NoticeSelector } from './notice-selector'; +import { NoticeActionee } from './notice-actionee'; + +const integrateNotice = () => { + api.internals.register(NoticeSelector.NOTICE, NoticeActionee); +}; + +export default integrateNotice; diff --git a/src/analytics/script/integration/component/pagination/integrate.js b/src/analytics/script/integration/component/pagination/integrate.js new file mode 100644 index 000000000..2ef7ea4a2 --- /dev/null +++ b/src/analytics/script/integration/component/pagination/integrate.js @@ -0,0 +1,11 @@ +import api from '../../../../api'; +import { PaginationSelector } from './pagination-selector'; +import { PaginationActionee } from './pagination-actionee'; +import { PaginationLinkActionee } from './pagination-link-actionee'; + +const integratePagination = () => { + api.internals.register(PaginationSelector.PAGINATION, PaginationActionee); + api.internals.register(PaginationSelector.LINK, PaginationLinkActionee); +}; + +export default integratePagination; diff --git a/src/analytics/script/integration/component/quote/integrate.js b/src/analytics/script/integration/component/quote/integrate.js new file mode 100644 index 000000000..32d5b6d68 --- /dev/null +++ b/src/analytics/script/integration/component/quote/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { QuoteSelector } from './quote-selector'; +import { QuoteActionee } from './quote-actionee'; + +const integrateQuote = () => { + api.internals.register(QuoteSelector.QUOTE, QuoteActionee); +}; + +export default integrateQuote; diff --git a/src/analytics/script/integration/component/radio/integrate.js b/src/analytics/script/integration/component/radio/integrate.js new file mode 100644 index 000000000..eea226823 --- /dev/null +++ b/src/analytics/script/integration/component/radio/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { RadioSelector } from './radio-selector'; +import { RadioActionee } from './radio-actionee'; + +const integrateRadio = () => { + api.internals.register(RadioSelector.INPUT, RadioActionee); +}; + +export default integrateRadio; diff --git a/src/analytics/script/integration/component/search/integrate.js b/src/analytics/script/integration/component/search/integrate.js new file mode 100644 index 000000000..a3e3366a2 --- /dev/null +++ b/src/analytics/script/integration/component/search/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { SearchSelector } from './search-selector'; +import { SearchActionee } from './search-actionee'; + +const integrateSearch = () => { + api.internals.register(SearchSelector.SEARCH_BAR, SearchActionee); +}; + +export default integrateSearch; diff --git a/src/analytics/script/integration/component/select/integrate.js b/src/analytics/script/integration/component/select/integrate.js new file mode 100644 index 000000000..0fe6d0893 --- /dev/null +++ b/src/analytics/script/integration/component/select/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { SelectSelector } from './select-selector'; +import { SelectActionee } from './select-actionee'; + +const integrateSelect = () => { + api.internals.register(SelectSelector.SELECT, SelectActionee); +}; + +export default integrateSelect; diff --git a/src/analytics/script/integration/component/share/integrate.js b/src/analytics/script/integration/component/share/integrate.js new file mode 100644 index 000000000..12d6d9074 --- /dev/null +++ b/src/analytics/script/integration/component/share/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { ShareSelector } from './share-selector'; +import { ShareActionee } from './share-actionee'; + +const integrateShare = () => { + api.internals.register(ShareSelector.SHARE, ShareActionee); +}; + +export default integrateShare; diff --git a/src/analytics/script/integration/component/sidemenu/integrate.js b/src/analytics/script/integration/component/sidemenu/integrate.js new file mode 100644 index 000000000..a86214dcc --- /dev/null +++ b/src/analytics/script/integration/component/sidemenu/integrate.js @@ -0,0 +1,15 @@ +import api from '../../../../api'; +import { SidemenuSelector } from './sidemenu-selector'; +import { SidemenuActionee } from './sidemenu-actionee'; +import { SidemenuLinkActionee } from './sidemenu-link-actionee'; +import { SidemenuSectionActionee } from './sidemenu-section-actionee'; + +const integrateSidemenu = () => { + if (api.sidemenu) { + api.internals.register(SidemenuSelector.SIDEMENU, SidemenuActionee); + api.internals.register(SidemenuSelector.LINK, SidemenuLinkActionee); + api.internals.register(api.sidemenu.SidemenuSelector.COLLAPSE, SidemenuSectionActionee); + } +}; + +export default integrateSidemenu; diff --git a/src/analytics/script/integration/component/stepper/integrate.js b/src/analytics/script/integration/component/stepper/integrate.js new file mode 100644 index 000000000..672767b06 --- /dev/null +++ b/src/analytics/script/integration/component/stepper/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { StepperSelector } from './stepper-selector'; +import { StepperActionee } from './stepper-actionee'; + +const integrateStepper = () => { + api.internals.register(StepperSelector.STEPPER, StepperActionee); +}; + +export default integrateStepper; diff --git a/src/analytics/script/integration/component/summary/integrate.js b/src/analytics/script/integration/component/summary/integrate.js new file mode 100644 index 000000000..1be053a1d --- /dev/null +++ b/src/analytics/script/integration/component/summary/integrate.js @@ -0,0 +1,13 @@ +import api from '../../../../api'; +import { SummarySelector } from './summary-selector'; +import { SummaryActionee } from './summary-actionee'; +import { SummaryLinkActionee } from './summary-link-actionee'; +import { SummarySectionActionee } from './summary-section-actionee'; + +const integrateSummary = () => { + api.internals.register(SummarySelector.SUMMARY, SummaryActionee); + api.internals.register(SummarySelector.LINK, SummaryLinkActionee); + api.internals.register(SummarySelector.ITEM, SummarySectionActionee); +}; + +export default integrateSummary; diff --git a/src/analytics/script/integration/component/tab/integrate.js b/src/analytics/script/integration/component/tab/integrate.js new file mode 100644 index 000000000..c1ef236c2 --- /dev/null +++ b/src/analytics/script/integration/component/tab/integrate.js @@ -0,0 +1,10 @@ +import api from '../../../../api'; +import { TabActionee } from './tab-actionee'; + +const integrateTab = () => { + if (api.tab) { + api.internals.register(api.tab.TabSelector.PANEL, TabActionee); + } +}; + +export default integrateTab; diff --git a/src/analytics/script/integration/component/table/integrate.js b/src/analytics/script/integration/component/table/integrate.js new file mode 100644 index 000000000..1b9b64565 --- /dev/null +++ b/src/analytics/script/integration/component/table/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { TableSelector } from './table-selector'; +import { TableActionee } from './table-actionee'; + +const integrateTable = () => { + api.internals.register(TableSelector.TABLE, TableActionee); +}; + +export default integrateTable; diff --git a/src/analytics/script/integration/component/tag/integrate.js b/src/analytics/script/integration/component/tag/integrate.js new file mode 100644 index 000000000..af6927cd2 --- /dev/null +++ b/src/analytics/script/integration/component/tag/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { TagSelector } from './tag-selector'; +import { TagActionee } from './tag-actionee'; + +const integrateTag = () => { + api.internals.register(TagSelector.TAG, TagActionee); +}; + +export default integrateTag; diff --git a/src/analytics/script/integration/component/tile/integrate.js b/src/analytics/script/integration/component/tile/integrate.js new file mode 100644 index 000000000..6511c40e0 --- /dev/null +++ b/src/analytics/script/integration/component/tile/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { TileSelector } from './tile-selector'; +import { TileActionee } from './tile-actionee'; + +const integrateTile = () => { + api.internals.register(TileSelector.TILE, TileActionee); +}; + +export default integrateTile; diff --git a/src/analytics/script/integration/component/toggle/integrate.js b/src/analytics/script/integration/component/toggle/integrate.js new file mode 100644 index 000000000..4e7fa640a --- /dev/null +++ b/src/analytics/script/integration/component/toggle/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { ToggleSelector } from './toggle-selector'; +import { ToggleActionee } from './toggle-actionee'; + +const integrateToggle = () => { + api.internals.register(ToggleSelector.INPUT, ToggleActionee); +}; + +export default integrateToggle; diff --git a/src/analytics/script/integration/component/transcription/integrate.js b/src/analytics/script/integration/component/transcription/integrate.js new file mode 100644 index 000000000..62632e2e9 --- /dev/null +++ b/src/analytics/script/integration/component/transcription/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { TranscriptionSelector } from './transcription-selector'; +import { TranscriptionActionee } from './transcription-actionee'; + +const integrateTranscription = () => { + api.internals.register(TranscriptionSelector.COLLAPSE, TranscriptionActionee); +}; + +export default integrateTranscription; diff --git a/src/analytics/script/integration/component/transcription/transcription-selector.js b/src/analytics/script/integration/component/transcription/transcription-selector.js index f30378395..a40232b57 100644 --- a/src/analytics/script/integration/component/transcription/transcription-selector.js +++ b/src/analytics/script/integration/component/transcription/transcription-selector.js @@ -1,7 +1,10 @@ import api from '../../../../api'; +const TRANSCRIPTION = api.internals.ns.selector('transcription'); +const COLLAPSE = api.internals.ns.selector('collapse'); + export const TranscriptionSelector = { - TRANSCRIPTION: api.internals.ns.selector('transcription'), - COLLAPSE: `${api.internals.ns.selector('transcription')} ${api.internals.ns.selector('collapse')}`, - TITLE: api.internals.ns.selector('transcription__title') + TRANSCRIPTION: TRANSCRIPTION, + COLLAPSE: `${TRANSCRIPTION} > ${COLLAPSE}, ${TRANSCRIPTION} > *:not(${TRANSCRIPTION}, ${COLLAPSE}) > ${COLLAPSE}, ${TRANSCRIPTION} > *:not(${TRANSCRIPTION}, ${COLLAPSE}) > *:not(${TRANSCRIPTION}, ${COLLAPSE}) > ${COLLAPSE}`, + TITLE: `${TRANSCRIPTION}__title` }; diff --git a/src/analytics/script/integration/component/translate/integrate.js b/src/analytics/script/integration/component/translate/integrate.js new file mode 100644 index 000000000..2a1ef0cc7 --- /dev/null +++ b/src/analytics/script/integration/component/translate/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { TranslateSelector } from './translate-selector'; +import { TranslateActionee } from './translate-actionee'; + +const integrateTranslate = () => { + api.internals.register(TranslateSelector.COLLAPSE, TranslateActionee); +}; + +export default integrateTranslate; diff --git a/src/analytics/script/integration/component/translate/translate-selector.js b/src/analytics/script/integration/component/translate/translate-selector.js index bd1634479..548dfb3bc 100644 --- a/src/analytics/script/integration/component/translate/translate-selector.js +++ b/src/analytics/script/integration/component/translate/translate-selector.js @@ -1,5 +1,9 @@ import api from '../../../../api'; +const TRANSLATE = api.internals.ns.selector('translate'); +const COLLAPSE = api.internals.ns.selector('collapse'); + export const TranslateSelector = { - BUTTON: api.internals.ns.selector('translate__btn') + BUTTON: `${TRANSLATE}__btn`, + COLLAPSE: `${TRANSLATE} > ${COLLAPSE}, ${TRANSLATE} > *:not(${TRANSLATE}, ${COLLAPSE}) > ${COLLAPSE}, ${TRANSLATE} > *:not(${TRANSLATE}, ${COLLAPSE}) > *:not(${TRANSLATE}, ${COLLAPSE}) > ${COLLAPSE}` }; diff --git a/src/analytics/script/integration/component/upload/integrate.js b/src/analytics/script/integration/component/upload/integrate.js new file mode 100644 index 000000000..57b4a8858 --- /dev/null +++ b/src/analytics/script/integration/component/upload/integrate.js @@ -0,0 +1,9 @@ +import api from '../../../../api'; +import { UploadSelector } from './upload-selector'; +import { UploadActionee } from './upload-actionee'; + +const integrateUpload = () => { + api.internals.register(UploadSelector.UPLOAD, UploadActionee); +}; + +export default integrateUpload; diff --git a/src/component/accordion/index.js b/src/component/accordion/index.js index e9ca2cbe2..afbeb9493 100644 --- a/src/component/accordion/index.js +++ b/src/component/accordion/index.js @@ -1,8 +1,10 @@ import api from './api.js'; +import { Accordion } from './script/accordion/accordion'; import { AccordionsGroup } from './script/accordion/accordions-group.js'; import { AccordionSelector } from './script/accordion/accordion-selector.js'; api.accordion = { + Accordion: Accordion, AccordionSelector: AccordionSelector, AccordionsGroup: AccordionsGroup }; diff --git a/src/component/accordion/main.js b/src/component/accordion/main.js index ec11c9209..9b663d41f 100644 --- a/src/component/accordion/main.js +++ b/src/component/accordion/main.js @@ -1,5 +1,6 @@ import api from './index.js'; api.internals.register(api.accordion.AccordionSelector.GROUP, api.accordion.AccordionsGroup); +api.internals.register(api.accordion.AccordionSelector.ACCORDION, api.accordion.Accordion); export default api; diff --git a/src/component/accordion/script/accordion/accordion-selector.js b/src/component/accordion/script/accordion/accordion-selector.js index debb40871..02f8e315b 100644 --- a/src/component/accordion/script/accordion/accordion-selector.js +++ b/src/component/accordion/script/accordion/accordion-selector.js @@ -1,6 +1,11 @@ import api from '../../api.js'; +const ACCORDION = api.internals.ns.selector('accordion'); +const COLLAPSE = api.internals.ns.selector('collapse'); + export const AccordionSelector = { GROUP: api.internals.ns.selector('accordions-group'), - COLLAPSE: `${api.internals.ns.selector('accordion')} > ${api.internals.ns.selector('collapse')}` + ACCORDION: ACCORDION, + COLLAPSE: `${ACCORDION} > ${COLLAPSE}, ${ACCORDION} > *:not(${ACCORDION}, ${COLLAPSE}) > ${COLLAPSE}, ${ACCORDION} > *:not(${ACCORDION}, ${COLLAPSE}) > *:not(${ACCORDION}, ${COLLAPSE}) > ${COLLAPSE}`, + BUTTON: `${ACCORDION}__btn` }; diff --git a/src/component/accordion/script/accordion/accordion.js b/src/component/accordion/script/accordion/accordion.js new file mode 100644 index 000000000..97a0a6b9e --- /dev/null +++ b/src/component/accordion/script/accordion/accordion.js @@ -0,0 +1,15 @@ +import api from '../../api.js'; +import { AccordionSelector } from './accordion-selector'; + +class Accordion extends api.core.Instance { + static get instanceClassName () { + return 'Accordion'; + } + + get collapsePrimary () { + const buttons = this.element.children.map(child => child.getInstance('CollapseButton')).filter(button => button !== null && button.hasClass(AccordionSelector.BUTTON)); + return buttons[0]; + } +} + +export { Accordion }; diff --git a/src/component/accordion/script/accordion/accordions-group.js b/src/component/accordion/script/accordion/accordions-group.js index 3fb7d204f..4aa74b32c 100644 --- a/src/component/accordion/script/accordion/accordions-group.js +++ b/src/component/accordion/script/accordion/accordions-group.js @@ -7,7 +7,7 @@ class AccordionsGroup extends api.core.CollapsesGroup { } validate (member) { - return member.node.matches(AccordionSelector.COLLAPSE); + return super.validate(member) && member.node.matches(AccordionSelector.COLLAPSE); } } diff --git a/src/component/breadcrumb/script/breadcrumb/breadcrumb-selector.js b/src/component/breadcrumb/script/breadcrumb/breadcrumb-selector.js index 907ffdbd7..e4f6642cd 100644 --- a/src/component/breadcrumb/script/breadcrumb/breadcrumb-selector.js +++ b/src/component/breadcrumb/script/breadcrumb/breadcrumb-selector.js @@ -1,5 +1,6 @@ import api from '../../api.js'; export const BreadcrumbSelector = { - BREADCRUMB: api.internals.ns.selector('breadcrumb') + BREADCRUMB: api.internals.ns.selector('breadcrumb'), + BUTTON: api.internals.ns.selector('breadcrumb__button') }; diff --git a/src/component/breadcrumb/script/breadcrumb/breadcrumb.js b/src/component/breadcrumb/script/breadcrumb/breadcrumb.js index 4ed91a1cb..f1d6d0935 100644 --- a/src/component/breadcrumb/script/breadcrumb/breadcrumb.js +++ b/src/component/breadcrumb/script/breadcrumb/breadcrumb.js @@ -1,4 +1,5 @@ import api from '../../api.js'; +import { BreadcrumbSelector } from './breadcrumb-selector.js'; class Breadcrumb extends api.core.Instance { constructor () { @@ -72,6 +73,11 @@ class Breadcrumb extends api.core.Instance { if (!link) return; if (document.activeElement !== link) this._focus(); } + + get collapsePrimary () { + const buttons = this.element.children.map(child => child.getInstance('CollapseButton')).filter(button => button !== null && button.hasClass(BreadcrumbSelector.BUTTON)); + return buttons[0]; + } } export { Breadcrumb }; diff --git a/src/component/header/example/sample/header.ejs b/src/component/header/example/sample/header.ejs index c3e457415..45c8fcbde 100755 --- a/src/component/header/example/sample/header.ejs +++ b/src/component/header/example/sample/header.ejs @@ -59,8 +59,8 @@ if (header.links !== undefined || header.search) { : header.search; tools.search.id = header.searchId || uniqueId('search'); - tools.search.modalId = uniqueId('modal'), - tools.search.btnId = uniqueId('button') + tools.search.modalId = tools.search.modalId || uniqueId('modal'), + tools.search.btnId = tools.search.btnId || uniqueId('button') } } @@ -88,8 +88,9 @@ if (header.navigation !== undefined) { if (hasMenu) { hasNavbar = true; - menu.modalId = uniqueId('modal'); - menu.id = uniqueId('button'); + const headerMenu = header.menu || {}; + menu.modalId = headerMenu.modalId || uniqueId('modal'); + menu.id = headerMenu.id || uniqueId('button'); if (header.navigation !== undefined) { menu.navigation.id = header.navigationId || uniqueId('navigation'); diff --git a/src/component/header/script/header/header-modal.js b/src/component/header/script/header/header-modal.js index 3153253cb..b6f528536 100644 --- a/src/component/header/script/header/header-modal.js +++ b/src/component/header/script/header/header-modal.js @@ -15,14 +15,15 @@ class HeaderModal extends api.core.Instance { } resize () { - if (this.isBreakpoint(api.core.Breakpoints.LG)) this.unqualify(); - else this.qualify(); + if (this.isBreakpoint(api.core.Breakpoints.LG)) this.deactivateModal(); + else this.activateModal(); } - qualify () { + activateModal () { this.setAttribute('role', 'dialog'); const modal = this.element.getInstance('Modal'); if (!modal) return; + modal.isEnabled = true; const buttons = modal.buttons; let id = ''; for (const button of buttons) { @@ -33,9 +34,11 @@ class HeaderModal extends api.core.Instance { this.listen('click', this._clickHandling, { capture: true }); } - unqualify () { + deactivateModal () { const modal = this.element.getInstance('Modal'); - if (modal) modal.conceal(); + if (!modal) return; + modal.conceal(); + modal.isEnabled = false; this.removeAttribute('role'); this.removeAttribute('aria-labelledby'); this.unlisten('click', this._clickHandling, { capture: true }); diff --git a/src/component/header/template/ejs/tools.ejs b/src/component/header/template/ejs/tools.ejs index a81ee6f33..9092ec386 100644 --- a/src/component/header/template/ejs/tools.ejs +++ b/src/component/header/template/ejs/tools.ejs @@ -26,7 +26,7 @@ <% if (tools.translate !== undefined) { %> - <%- include ('../../../translate/template/ejs/translate.ejs', {translate: tools.translate}); %> + <%- include('../../../translate/template/ejs/translate.ejs', { translate: tools.translate }); %> <% } %>
<% } %> diff --git a/src/component/main.js b/src/component/main.js index b88c60a35..5a627a8f4 100644 --- a/src/component/main.js +++ b/src/component/main.js @@ -11,6 +11,7 @@ import './navigation/main.js'; import './tab/main.js'; import './table/main.js'; import './tag/main.js'; +import './transcription/main.js'; import './tile/main.js'; import './header/main.js'; import './display/main.js'; diff --git a/src/component/modal/script/modal/modal.js b/src/component/modal/script/modal/modal.js index 66eab3b74..5940f7d12 100644 --- a/src/component/modal/script/modal/modal.js +++ b/src/component/modal/script/modal/modal.js @@ -16,7 +16,7 @@ class Modal extends api.core.Disclosure { init () { super.init(); - this.listen('click', this.click.bind(this)); + this.listenClick(); this.listenKey(api.core.KeyCodes.ESCAPE, this.conceal.bind(this, false, false), true, true); } @@ -24,7 +24,7 @@ class Modal extends api.core.Disclosure { return this.element.getDescendantInstances('ModalBody', 'Modal')[0]; } - click (e) { + handleClick (e) { if (e.target === this.node && this.getAttribute(ModalAttribute.CONCEALING_BACKDROP) !== 'false') this.conceal(); } @@ -45,6 +45,10 @@ class Modal extends api.core.Disclosure { if (this.body) this.body.deactivate(); return true; } + + _electPrimary (candidates) { + return null; + } } export { Modal }; diff --git a/src/component/navigation/script/navigation/navigation-item.js b/src/component/navigation/script/navigation/navigation-item.js index d176f589f..a79bdb8a9 100644 --- a/src/component/navigation/script/navigation/navigation-item.js +++ b/src/component/navigation/script/navigation/navigation-item.js @@ -42,6 +42,11 @@ class NavigationItem extends api.core.Instance { if (value) api.internals.dom.addClass(this.element.node, NavigationSelector.ITEM_RIGHT); else api.internals.dom.removeClass(this.element.node, NavigationSelector.ITEM_RIGHT); } + + get collapsePrimary () { + const buttons = this.element.children.map(child => child.getInstance('CollapseButton')).filter(button => button !== null && (button.hasClass(NavigationSelector.BUTTON) || button.hasClass(NavigationSelector.TRANSLATE_BUTTON))); + return buttons[0]; + } } export { NavigationItem }; diff --git a/src/component/navigation/script/navigation/navigation-selector.js b/src/component/navigation/script/navigation/navigation-selector.js index 06d5d44d2..5479d6253 100644 --- a/src/component/navigation/script/navigation/navigation-selector.js +++ b/src/component/navigation/script/navigation/navigation-selector.js @@ -1,9 +1,14 @@ import api from '../../api.js'; +const ITEM = api.internals.ns.selector('nav__item'); +const COLLAPSE = api.internals.ns.selector('collapse'); + export const NavigationSelector = { NAVIGATION: api.internals.ns.selector('nav'), - COLLAPSE: `${api.internals.ns.selector('nav__item')} > ${api.internals.ns.selector('collapse')}`, - ITEM: api.internals.ns.selector('nav__item'), - ITEM_RIGHT: api.internals.ns('nav__item--align-right'), - MENU: api.internals.ns.selector('menu') + COLLAPSE: `${ITEM} > ${COLLAPSE}, ${ITEM} > *:not(${ITEM}, ${COLLAPSE}) > ${COLLAPSE}, ${ITEM} > *:not(${ITEM}, ${COLLAPSE}) > *:not(${ITEM}, ${COLLAPSE}) > ${COLLAPSE}`, + ITEM: ITEM, + ITEM_RIGHT: `${ITEM}--align-right`, + MENU: api.internals.ns.selector('menu'), + BUTTON: api.internals.ns.selector('nav__btn'), + TRANSLATE_BUTTON: api.internals.ns.selector('translate__btn') }; diff --git a/src/component/navigation/script/navigation/navigation.js b/src/component/navigation/script/navigation/navigation.js index 378fe7b72..166dc6c8f 100644 --- a/src/component/navigation/script/navigation/navigation.js +++ b/src/component/navigation/script/navigation/navigation.js @@ -13,11 +13,11 @@ class Navigation extends api.core.CollapsesGroup { this.out = false; this.listen('focusout', this.focusOutHandler.bind(this)); this.listen('mousedown', this.mouseDownHandler.bind(this)); - this.listen('click', this.clickHandler.bind(this), { capture: true }); + this.listenClick({ capture: true }); } validate (member) { - return member.element.node.matches(NavigationSelector.COLLAPSE); + return super.validate(member) && member.element.node.matches(NavigationSelector.COLLAPSE); } mouseDownHandler (e) { @@ -70,7 +70,7 @@ class Navigation extends api.core.CollapsesGroup { get index () { return super.index; } set index (value) { - if (value === -1 && this.current !== null && this.current.hasFocus) this.current.focus(); + if (value === -1 && this.current && this.current.hasFocus) this.current.focus(); super.index = value; } } diff --git a/src/component/navigation/style/scheme/_default.scss b/src/component/navigation/style/scheme/_default.scss index 494359118..6d19d4fad 100644 --- a/src/component/navigation/style/scheme/_default.scss +++ b/src/component/navigation/style/scheme/_default.scss @@ -20,7 +20,7 @@ } &__btn { - &[aria-expanded="true"] { + &[aria-expanded="true"]:not(:disabled) { @include respond-from(lg) { @include color.text(active blue-france, (legacy: $legacy)); @include color.background(open blue-france, (legacy: $legacy)); diff --git a/src/component/password/script/password/password-toggle.js b/src/component/password/script/password/password-toggle.js index 9be0164ff..3bbe8072d 100644 --- a/src/component/password/script/password/password-toggle.js +++ b/src/component/password/script/password/password-toggle.js @@ -7,7 +7,7 @@ class PasswordToggle extends api.core.Instance { } init () { - this.listen('click', this.toggle.bind(this)); + this.listenClick(); this.ascend(PasswordEmission.ADJUST, this.width); this.isSwappingFont = true; this._isChecked = this.isChecked; @@ -27,7 +27,7 @@ class PasswordToggle extends api.core.Instance { this.ascend(PasswordEmission.TOGGLE, value); } - toggle () { + handleClick () { this.isChecked = !this._isChecked; } diff --git a/src/component/sidemenu/example/sample/sidemenu.ejs b/src/component/sidemenu/example/sample/sidemenu.ejs index 1aa1e1e82..cd75fb5db 100755 --- a/src/component/sidemenu/example/sample/sidemenu.ejs +++ b/src/component/sidemenu/example/sample/sidemenu.ejs @@ -53,6 +53,7 @@ function menu(level, active, collapsable) { let data = { items: items(0), title: sidemenu.title || 'Titre de rubrique', + titleId: uniqueId('sidemenu-title'), modifier: sidemenu.modifier, collapseId: uniqueId('sidemenu') } diff --git a/src/component/sidemenu/index.js b/src/component/sidemenu/index.js index 83a08af61..c6b8a595b 100644 --- a/src/component/sidemenu/index.js +++ b/src/component/sidemenu/index.js @@ -1,9 +1,11 @@ import api from './api.js'; import { SidemenuList } from './script/sidemenu/sidemenu-list.js'; import { SidemenuSelector } from './script/sidemenu/sidemenu-selector.js'; +import { SidemenuItem } from './script/sidemenu/sidemenu-item'; api.sidemenu = { SidemenuList: SidemenuList, + SidemenuItem: SidemenuItem, SidemenuSelector: SidemenuSelector }; diff --git a/src/component/sidemenu/main.js b/src/component/sidemenu/main.js index 284203295..09dba108a 100644 --- a/src/component/sidemenu/main.js +++ b/src/component/sidemenu/main.js @@ -1,5 +1,6 @@ import api from './index.js'; api.internals.register(api.sidemenu.SidemenuSelector.LIST, api.sidemenu.SidemenuList); +api.internals.register(api.sidemenu.SidemenuSelector.ITEM, api.sidemenu.SidemenuItem); export default api; diff --git a/src/component/sidemenu/script/sidemenu/sidemenu-item.js b/src/component/sidemenu/script/sidemenu/sidemenu-item.js new file mode 100644 index 000000000..f5dce703e --- /dev/null +++ b/src/component/sidemenu/script/sidemenu/sidemenu-item.js @@ -0,0 +1,15 @@ +import api from '../../api.js'; +import { SidemenuSelector } from './sidemenu-selector.js'; + +class SidemenuItem extends api.core.Instance { + static get instanceClassName () { + return 'SidemenuItem'; + } + + get collapsePrimary () { + const buttons = this.element.children.map(child => child.getInstance('CollapseButton')).filter(button => button !== null && button.hasClass(SidemenuSelector.BUTTON)); + return buttons[0]; + } +} + +export { SidemenuItem }; diff --git a/src/component/sidemenu/script/sidemenu/sidemenu-list.js b/src/component/sidemenu/script/sidemenu/sidemenu-list.js index 8770fab62..827d9bc51 100644 --- a/src/component/sidemenu/script/sidemenu/sidemenu-list.js +++ b/src/component/sidemenu/script/sidemenu/sidemenu-list.js @@ -7,7 +7,7 @@ class SidemenuList extends api.core.CollapsesGroup { } validate (member) { - return member.node.matches(SidemenuSelector.COLLAPSE); + return super.validate(member) && member.node.matches(SidemenuSelector.COLLAPSE); } } diff --git a/src/component/sidemenu/script/sidemenu/sidemenu-selector.js b/src/component/sidemenu/script/sidemenu/sidemenu-selector.js index c2a1a496d..40af3f0d9 100644 --- a/src/component/sidemenu/script/sidemenu/sidemenu-selector.js +++ b/src/component/sidemenu/script/sidemenu/sidemenu-selector.js @@ -1,6 +1,11 @@ import api from '../../api.js'; +const ITEM = api.internals.ns.selector('sidemenu__item'); +const COLLAPSE = api.internals.ns.selector('collapse'); + export const SidemenuSelector = { LIST: api.internals.ns.selector('sidemenu__list'), - COLLAPSE: `${api.internals.ns.selector('sidemenu__item')} > ${api.internals.ns.selector('collapse')}` + COLLAPSE: `${ITEM} > ${COLLAPSE}, ${ITEM} > *:not(${ITEM}, ${COLLAPSE}) > ${COLLAPSE}, ${ITEM} > *:not(${ITEM}, ${COLLAPSE}) > *:not(${ITEM}, ${COLLAPSE}) > ${COLLAPSE}`, + ITEM: api.internals.ns.selector('sidemenu__item'), + BUTTON: api.internals.ns.selector('sidemenu__btn') }; diff --git a/src/component/sidemenu/template/ejs/sidemenu.ejs b/src/component/sidemenu/template/ejs/sidemenu.ejs index 3059f7e78..4fda00596 100644 --- a/src/component/sidemenu/template/ejs/sidemenu.ejs +++ b/src/component/sidemenu/template/ejs/sidemenu.ejs @@ -13,11 +13,11 @@ <% let sidemenu = locals.sidemenu || {}; %> <% eval(include('../../../../core/index.ejs')); %> -