qc-trousse-sdg 1.2.5-dev → 1.3.0-develop.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +18 -3
  2. package/dist/css/qc-sdg-design-tokens.min.css +1 -1
  3. package/dist/css/qc-sdg-no-grid.min.css +1 -1
  4. package/dist/css/qc-sdg.min.css +1 -1
  5. package/dist/img/QUEBEC_blanc.svg +1 -1
  6. package/dist/img/QUEBEC_couleur.svg +24 -0
  7. package/dist/js/qc-sdg.min.js +1 -1
  8. package/package.json +23 -18
  9. package/public/css/qc-doc-sdg.css +247 -335
  10. package/public/css/qc-sdg-design-tokens.css +111 -64
  11. package/public/css/qc-sdg-no-grid.css +932 -428
  12. package/public/css/qc-sdg.css +941 -609
  13. package/public/img/QUEBEC_blanc.svg +1 -1
  14. package/public/img/QUEBEC_couleur.svg +24 -0
  15. package/public/img/ampoule.svg +1 -0
  16. package/public/img/note.svg +1 -0
  17. package/public/img/piv-MCE-theme-clair.svg +79 -0
  18. package/public/img/piv-MCE-theme-sombre.svg +62 -0
  19. package/public/img/piv-bas-MCE-theme-clair.png +0 -0
  20. package/public/img/piv-bas-MCE-theme-sombre.png +0 -0
  21. package/public/img/piv-logo-pied-de-page.svg +37 -0
  22. package/public/index.html +871 -715
  23. package/public/js/qc-doc-exemple.js +9 -0
  24. package/public/js/qc-doc-sdg.js +6893 -3724
  25. package/public/js/qc-sdg.js +2103 -962
  26. package/rollup.config.js +58 -23
  27. package/src/doc/components/Code.svelte +69 -0
  28. package/src/doc/components/Exemple.svelte +71 -0
  29. package/src/doc/components/Switch.svelte +108 -0
  30. package/src/doc/components/TopNav.svelte +53 -0
  31. package/src/doc/components/color-doc.svelte +44 -0
  32. package/src/doc/qc-doc-sdg.js +25 -14
  33. package/src/doc/scss/_tables.scss +1 -2
  34. package/src/doc/scss/components/_button.scss +14 -14
  35. package/src/doc/scss/components/_code.scss +106 -4
  36. package/src/doc/scss/jQueryUI/_jquery-ui.autocomplete.scss +48 -0
  37. package/src/doc/scss/qc-doc-sdg.scss +76 -75
  38. package/src/sdg/components/Button/IconButton.svelte +29 -0
  39. package/src/sdg/components/Icon.svelte +39 -0
  40. package/src/sdg/components/{pivHeader.svelte → PivHeader/pivHeader.svelte} +49 -69
  41. package/src/sdg/components/SearchBar/searchBar.svelte +87 -0
  42. package/src/sdg/components/SearchInput/SearchInput.svelte +48 -0
  43. package/src/sdg/components/alert.svelte +40 -23
  44. package/src/sdg/components/componentWrapper.js +0 -3
  45. package/src/sdg/components/externalLink.svelte +92 -0
  46. package/src/sdg/components/notice.svelte +61 -34
  47. package/src/sdg/components/pivFooter.svelte +37 -36
  48. package/src/sdg/components/toTop.svelte +16 -10
  49. package/src/sdg/components/utils.js +28 -4
  50. package/src/sdg/qc-sdg.js +11 -3
  51. package/src/sdg/scss/_qc-sdg-lib.scss +3 -0
  52. package/src/sdg/scss/base/_accessibility.scss +4 -0
  53. package/src/sdg/scss/base/_colors.scss +10 -10
  54. package/src/sdg/scss/base/_figure.scss +14 -9
  55. package/src/sdg/scss/base/_fonts.scss +4 -4
  56. package/src/sdg/scss/base/_form.scss +7 -0
  57. package/src/sdg/scss/base/_layout.scss +45 -0
  58. package/src/sdg/scss/base/_lists.scss +5 -5
  59. package/src/sdg/scss/base/_shadings.scss +3 -11
  60. package/src/sdg/scss/base/_typography.scss +42 -25
  61. package/src/sdg/scss/components/_alert.scss +11 -34
  62. package/src/sdg/scss/components/_icons.scss +67 -38
  63. package/src/sdg/scss/components/_notice.scss +51 -44
  64. package/src/sdg/scss/components/_pivFooter.scss +35 -23
  65. package/src/sdg/scss/components/_pivHeader.scss +131 -154
  66. package/src/sdg/scss/components/_searchBar.scss +75 -0
  67. package/src/sdg/scss/components/_searchInput.scss +64 -0
  68. package/src/sdg/scss/components/_separator.scss +2 -5
  69. package/src/sdg/scss/components/_toTop.scss +4 -6
  70. package/src/sdg/scss/grid/_grid-lib.scss +516 -0
  71. package/src/sdg/scss/grid/_grid.scss +78 -0
  72. package/src/sdg/scss/lib/_functions.scss +78 -0
  73. package/src/sdg/scss/lib/_gridless-lib.scss +4 -0
  74. package/src/sdg/scss/lib/_mixins.scss +221 -0
  75. package/src/sdg/scss/qc-design-tokens.scss +31 -8
  76. package/src/sdg/scss/qc-sdg-utilities.scss +1 -0
  77. package/src/sdg/scss/qc-sdg.scss +1 -1
  78. package/src/sdg/scss/qc-sgd-no-grid.scss +20 -15
  79. package/src/sdg/scss/settings/_base.scss +58 -0
  80. package/src/sdg/scss/settings/_tokens.scss +145 -77
  81. package/src/sdg/scss/utilities/_display.scss +43 -3
  82. package/src/sdg/scss/utilities/_themes.scss +17 -0
  83. package/src/sdg/scss/vendor/modern-css-reset/src/reset.css +9 -8
  84. package/dist/img/logo-quebec-piv-footer.svg +0 -1
  85. package/dist/img/quebec-logo.svg +0 -13
  86. package/public/img/logo-quebec-piv-footer.svg +0 -1
  87. package/src/doc/components/code.svelte +0 -54
  88. package/src/sdg/scss/base/_grid.scss +0 -9
  89. package/src/sdg/scss/functions/_tokens.scss +0 -12
  90. package/src/sdg/scss/functions/_utils.scss +0 -44
  91. package/src/sdg/scss/modules/_grid.scss +0 -19
  92. package/src/sdg/scss/modules/_helpers.scss +0 -32
  93. package/src/sdg/scss/modules/_map.scss +0 -14
  94. package/src/sdg/scss/modules/_tokens.scss +0 -3
  95. package/src/sdg/scss/modules/_utils.scss +0 -55
  96. package/src/sdg/scss/settings/_grid.scss +0 -24
  97. package/src/sdg/scss/settings/_settings.scss +0 -12
@@ -0,0 +1,87 @@
1
+ <svelte:options customElement="{{
2
+ tag: 'qc-search-bar',
3
+ shadow: 'none',
4
+ props: {
5
+ value: {attribute: 'input-value', type:'String'},
6
+ name: {attribute: 'input-name', type:'String'},
7
+ pivBackground: {attribute: 'piv-background', type:'Boolean'},
8
+ }
9
+ }}" />
10
+
11
+ <script>
12
+ import {Utils} from "../utils";
13
+ import SearchInput from "../SearchInput/SearchInput.svelte";
14
+ import IconButton from "../Button/IconButton.svelte";
15
+
16
+ const
17
+ lang = Utils.getPageLanguage(),
18
+ inputDefaultPlaceholder = lang === "fr"
19
+ ? "Rechercher…"
20
+ : "Search",
21
+ submitDefaultAriaLabel = lang === "fr"
22
+ ? "Lancer la recherche"
23
+ : "Submit search"
24
+ ;
25
+ export let
26
+ value = '',
27
+ name = 'q',
28
+ pivBackground = false
29
+ ;
30
+
31
+ let defaultsAttributes = {
32
+ input: {
33
+ "placeholder": inputDefaultPlaceholder,
34
+ "aria-label": inputDefaultPlaceholder
35
+ },
36
+ submit: {
37
+ "aria-label": submitDefaultAriaLabel
38
+ }
39
+ },
40
+ inputProps = {},
41
+ submitProps = {}
42
+
43
+ $: [inputProps, submitProps] = computeFieldsAttributes($$restProps)
44
+ $: inputProps = {
45
+ "value": value,
46
+ "name": name,
47
+ ...inputProps
48
+ }
49
+
50
+ /**
51
+ * @param {{[p: string]: T}} restProps
52
+ */
53
+ function computeFieldsAttributes(restProps) {
54
+ return ["input","submit"]
55
+ .map(control => {
56
+ const prefix = `${control}-`;
57
+ return {
58
+ ...defaultsAttributes[control],
59
+ ...Object.fromEntries(Object
60
+ .entries(restProps)
61
+ .map(([k,v]) => k.startsWith(prefix)
62
+ ? [k.replace(prefix, ''),v]
63
+ : null
64
+ )
65
+ .filter(x => x) // élimine les éléments null
66
+ )
67
+ }
68
+ }
69
+ )
70
+ }
71
+
72
+
73
+ </script>
74
+ <div class="qc-search-bar"
75
+ class:piv-background={pivBackground}
76
+ >
77
+ <SearchInput {...inputProps}/>
78
+ {#if true}
79
+ <IconButton
80
+ type="submit"
81
+ iconColor={pivBackground ? 'blue-piv' : 'background'}
82
+ icon="loupe-piv-fine"
83
+ iconSize="md"
84
+ {...submitProps}
85
+ />
86
+ {/if}
87
+ </div>
@@ -0,0 +1,48 @@
1
+ <svelte:options customElement="{{
2
+ tag: 'qc-search-input',
3
+ shadow: 'none',
4
+ props: {
5
+ ariaLabel: {attribute:'aria-label'},
6
+ clearAriaLabel: {attribute: 'clear-aria-label'}
7
+ }
8
+ }}" />
9
+ <script>
10
+ import IconButton from "../Button/IconButton.svelte";
11
+ import {Utils} from "../utils";
12
+ const
13
+ lang = Utils.getPageLanguage();
14
+
15
+ export let
16
+ value,
17
+ ariaLabel = lang === "fr"
18
+ ? "Rechercher…"
19
+ : "Search_",
20
+ clearAriaLabel = lang === "fr"
21
+ ? "Effacer le texte"
22
+ : "Clear text"
23
+ ;
24
+ let searchInput;
25
+
26
+ </script>
27
+ <div class="qc-search-input">
28
+ <input bind:this={searchInput}
29
+ bind:value
30
+ type="search"
31
+ autocomplete="off"
32
+ {...(ariaLabel ? {"aria-label": ariaLabel} : {})}
33
+ {...$$restProps}
34
+ />
35
+ {#if value}
36
+ <IconButton type="button"
37
+ icon="clear-input"
38
+ iconColor="blue-piv"
39
+ iconSize="sm"
40
+ aria-label={clearAriaLabel}
41
+ on:click={e => {
42
+ e.preventDefault();
43
+ value = "";
44
+ searchInput.focus();
45
+ }}
46
+ />
47
+ {/if}
48
+ </div>
@@ -1,13 +1,25 @@
1
- <svelte:options customElement="qc-alert"/>
1
+ <svelte:options customElement="{{
2
+ tag:'qc-alert',
3
+ props: {
4
+ type : {attribute: 'type'},
5
+ maskable : {attribute: 'maskable'},
6
+ fullWidth : {attribute: 'full-width'},
7
+ content: {attribute: 'content'},
8
+ hide: {attribute: 'hide'},
9
+ }
10
+ }}"/>
2
11
 
3
12
  <script>
4
13
  import {Utils} from "./utils";
14
+ import Icon from "./Icon.svelte";
15
+ import IconButton from "./Button/IconButton.svelte";
5
16
 
6
17
  export let
7
18
  type = "general"
8
19
  , maskable = ""
9
20
  , content = ""
10
21
  , hide = "false"
22
+ , fullWidth = 'false'
11
23
  ;
12
24
 
13
25
  let
@@ -17,8 +29,8 @@
17
29
  ? type
18
30
  : 'general'
19
31
  , closeLabel = Utils.getPageLanguage() === 'fr'
20
- ? "Fermer"
21
- : "Close"
32
+ ? "Fermer l’alerte"
33
+ : "Close l’alerte"
22
34
  , warningLabel = Utils.getPageLanguage() === 'fr'
23
35
  ? "Information d'importance élevée"
24
36
  : "Information of high importance"
@@ -28,9 +40,12 @@
28
40
  , label = type === 'general'
29
41
  ? generalLabel
30
42
  : warningLabel
43
+ , containerClass
31
44
  ;
32
45
 
33
46
  $: hiddenFlag = hide === 'true'
47
+ $: containerClass = "qc-container" + (fullWidth === 'true' ? '-fluid' : '');
48
+
34
49
  function hideAlert() {
35
50
  hide='true'
36
51
  rootElement.dispatchEvent(
@@ -44,28 +59,30 @@
44
59
  {#if !hiddenFlag}
45
60
  <div bind:this={rootElement}
46
61
  class="qc-general-alert {typeClass}"
47
- role="alert"
48
- aria-label={label}>
49
- <div class="qc-container qc-general-alert-elements">
50
- <div class="qc-icon qc-{type}-alert-icon"
51
- aria-hidden="true"
52
- ></div>
53
- <div class="qc-alert-content">
54
- {@html content}
55
- <slot />
56
- </div>
57
- {#if maskable === "true"}
58
- <div class="qc-alert-close">
59
- <button type="button" class="qc-close" aria-label={closeLabel}
60
- on:click={hideAlert}>
61
- <span aria-hidden="true"
62
- class="qc-icon qc-xclose-blue qc-close-alert-icon"
63
- ></span>
64
- </button>
62
+ role="alert">
63
+ <div class={containerClass}>
64
+ <div class="qc-general-alert-elements">
65
+ <Icon type={type == 'warning' ? 'warning' : 'information'}
66
+ color="{type == 'general' ? 'blue-piv' : 'yellow-dark'}"
67
+ size="nm"
68
+ label={label}
69
+ />
70
+ <div class="qc-alert-content">
71
+ {@html content}
72
+ <slot />
65
73
  </div>
66
- {/if}
74
+ {#if maskable === "true"}
75
+ <IconButton aria-label={closeLabel}
76
+ on:click={hideAlert}
77
+ size="nm"
78
+ icon="clear-input"
79
+ iconSize="sm"
80
+ iconColor="text-primary"
81
+ />
82
+ {/if}
83
+ </div>
67
84
  </div>
68
85
  </div>
69
86
  {/if}
70
87
  <link rel='stylesheet'
71
- href='{Utils.cssRelativePath}{Utils.cssFileName}'>
88
+ href='{Utils.cssPath}'>
@@ -2,9 +2,6 @@
2
2
  Référence : https://github.com/sveltejs/svelte/issues/3852
3
3
  */
4
4
  export const customElements = {
5
- customFoo: function () {
6
- return "bar";
7
- },
8
5
  define: (tagName, CustomElement) => {
9
6
  class CustomElementWrapper extends CustomElement {
10
7
  static get observedAttributes() {
@@ -0,0 +1,92 @@
1
+ <svelte:options customElement="{{
2
+ tag:'qc-external-link',
3
+ shadow:'none',
4
+ props: {
5
+ externalIconAlt : {attribute: 'img-alt'}
6
+ }
7
+ }}"/>
8
+
9
+ <script>
10
+ import {Utils} from "./utils";
11
+ import {onMount} from "svelte";
12
+
13
+ export
14
+ let externalIconAlt = Utils.getPageLanguage() == "fr"
15
+ ? "Ce lien dirige vers un autre site."
16
+ : "This link directs to another site."
17
+ ;
18
+ let imgElement;
19
+
20
+ onMount(() => {
21
+ imgElement.parentElement.querySelectorAll('a').forEach(link => {
22
+
23
+ // Crée un TreeWalker pour parcourir uniquement les nœuds texte visibles
24
+ const walker = document.createTreeWalker(
25
+ link,
26
+ NodeFilter.SHOW_ALL,
27
+ {
28
+ acceptNode: node => {
29
+ if (node instanceof Element) {
30
+ if (node.hasAttribute('hidden')) {
31
+ return NodeFilter.FILTER_REJECT;
32
+ }
33
+ const style = window.getComputedStyle(node);
34
+ // Si l'élément est masqué par CSS (display ou visibility), on l'ignore
35
+ if (style.display === 'none'
36
+ || style.visibility === 'hidden'
37
+ || style.position === 'absolute') {
38
+ return NodeFilter.FILTER_REJECT;
39
+ }
40
+ }
41
+ if (!node instanceof Text) {
42
+ return NodeFilter.FILTER_SKIP
43
+ }
44
+ // Ignore les nœuds vides
45
+ if (!/\S/.test(node.textContent)) {
46
+ return NodeFilter.FILTER_SKIP;
47
+ }
48
+ return NodeFilter.FILTER_ACCEPT;
49
+ }
50
+ }
51
+ );
52
+
53
+ let lastTextNode = null;
54
+ while (walker.nextNode()) {
55
+ lastTextNode = walker.currentNode;
56
+ }
57
+
58
+ // S'il n'y a pas de nœud texte visible, on ne fait rien
59
+ if (!lastTextNode) return;
60
+
61
+ // Séparer le contenu du dernier nœud texte en deux parties :
62
+ // le préfixe (éventuel) et le dernier mot
63
+ const text = lastTextNode.textContent;
64
+ const regex = /^(.*\s)?(\S+)\s*$/m;
65
+ const match = text.match(regex);
66
+ if (!match) return;
67
+ const prefix = match[1] || "";
68
+ const lastWord = match[2];
69
+
70
+ // Crée un span avec white-space: nowrap pour empêcher le saut de ligne de l'image de lien externe
71
+ const span = document.createElement('span');
72
+ span.classList.add('img-wrap')
73
+ span.innerHTML = `${lastWord}`;
74
+ span.appendChild(imgElement)
75
+
76
+ // Met à jour le nœud texte : on garde le préfixe et on insère le span après
77
+ if (prefix) {
78
+ lastTextNode.textContent = prefix;
79
+ lastTextNode.parentNode.insertBefore(span, lastTextNode.nextSibling);
80
+ } else {
81
+ lastTextNode.parentNode.replaceChild(span, lastTextNode);
82
+ }
83
+ });
84
+ });
85
+ </script>
86
+ <span bind:this={imgElement}
87
+ role="img"
88
+ class="qc-ext-link-img"
89
+ aria-label={externalIconAlt}></span>
90
+
91
+
92
+
@@ -2,55 +2,82 @@
2
2
 
3
3
  <script>
4
4
  import { Utils } from "./utils"
5
- import { onMount } from "svelte";
5
+ import Icon from "./Icon.svelte";
6
6
 
7
7
  const
8
- defaultHeader = 'h2'
8
+ isFr = Utils.getPageLanguage() == 'fr'
9
+ , defaultHeader = 'h2'
9
10
  , defaultType = 'information'
10
- , types =
11
- [ 'information'
12
- , 'warning'
13
- , 'success'
14
- , 'error'
15
- ]
11
+ , typesDescriptions = {
12
+ 'advice': isFr ? "Avis conseil" : "Advisory notice",
13
+ 'note': isFr ? "Avis explicatif" : "Explanatory notice"
14
+ , 'information': isFr ? "Avis général" : "General notice"
15
+ , 'warning': isFr ? "Avis d’avertissement" : "Warning notice"
16
+ , 'success': isFr ? "Avis de réussite" : "Success notice"
17
+ , 'error': isFr ? "Avis d’erreur" : "Error notice"
18
+ }
19
+ , types = Object.keys(typesDescriptions);
20
+
21
+ let noticeElement;
16
22
  export let
17
- title = ""
18
- , type = defaultType
19
- , content = ""
20
- , header = defaultHeader
21
-
22
- onMount(() => {
23
- header = header.match(/h[1-6]/)
24
- ? header
25
- : defaultHeader
26
- ;
27
- type = types.includes(type)
28
- ? type
29
- : defaultType
30
- ;
31
- })
23
+ title = ""
24
+ , type = defaultType
25
+ , content = ""
26
+ , header = defaultHeader
27
+ , icon;
28
+
29
+ $: header = header.match(/h[1-6]/)
30
+ ? header
31
+ : defaultHeader;
32
+
33
+ $: type = types.includes(type)
34
+ ? type
35
+ : defaultType;
36
+
37
+ $: role = type === "success"
38
+ ? "status"
39
+ : (type === "error" ? "alert" : null);
40
+
41
+ $: if (role) {
42
+ if (noticeElement) {
43
+ const tempNodes = Array.from(noticeElement.childNodes);
44
+ // console.log("temp: ",tempNodes);
45
+ noticeElement.innerHTML = "";
46
+ // Réinsère le contenu pour qu'il soit détecté par le lecteur d'écran.
47
+ tempNodes.forEach(node => noticeElement.appendChild(node)); }
48
+ }
49
+
50
+ $: shouldUseIcon = type === "advice" || type === "note";
51
+ // Si le type est "advice" ou "note", on force "neutral" (le gris), sinon on garde le type normal
52
+ $: computedType = shouldUseIcon ? "neutral" : type;
53
+ $: iconType = shouldUseIcon ? (icon ?? "note") : type;
54
+ $: iconLabel = typesDescriptions[type] ?? typesDescriptions['information'];
55
+
56
+
32
57
  </script>
33
58
 
34
59
  <!-- TODO Confirmer tabindex. On pense que c'est important de recevoir le focus (notamment dans les formulaires) en fait pour nous c'est très important, sinon en mode formulaire au lecteur écran (nav avec TAB, ce n'est jamais lu). -->
35
60
  <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
36
- <div class="qc-component qc-notice qc-{type}"
61
+ <div class="qc-component qc-notice qc-{computedType}"
37
62
  tabindex="0">
38
63
  <div class="icon-container">
39
- <div aria-hidden="true"
40
- class="qc-icon qc-{type}">
64
+ <div class="qc-icon">
65
+ <Icon type="{iconType}"
66
+ label={iconLabel}
67
+ size="nm"
68
+ />
41
69
  </div>
42
70
  </div>
43
71
  <div class="content-container">
44
- <div class="content">
45
- <svelte:element this={header}
46
- class="title">
47
- {title}
48
- </svelte:element>
49
- <div class="text">
72
+ <div class="content" {role} bind:this={noticeElement}>
73
+ {#if title}
74
+ <svelte:element this={header}>
75
+ {@html title}
76
+ </svelte:element>
77
+ {/if}
50
78
  {@html content}
51
79
  <slot />
52
- </div>
53
80
  </div>
54
81
  </div>
55
82
  </div>
56
- <link rel='stylesheet' href='{Utils.cssRelativePath}{Utils.cssFileName}'>
83
+ <link rel='stylesheet' href='{Utils.cssPath}'>
@@ -2,11 +2,14 @@
2
2
  tag: 'qc-piv-footer'
3
3
  , props: {
4
4
  logoUrl : {attribute: 'logo-url'}
5
+ , logoSrc : {attribute: 'logo-src'}
6
+ , logoSrcDarkTheme: {attribute: 'logo-src-dark-theme'}
5
7
  , logoAlt : {attribute: 'logo-alt'}
6
- , logoWidth : {attribute: 'logo-width'}
7
- , logoHeight : {attribute: 'logo-height'}
8
- , copyrightText : {attribute: 'copyrightText'}
8
+ , logoWidth: {attribute: 'logo-width'}
9
+ , logoHeight: {attribute: 'logo-height'}
10
+ , copyrightText : {attribute: 'copyright-text'}
9
11
  , copyrightUrl : {attribute: 'copyright-url'}
12
+
10
13
  }}
11
14
  }}" />
12
15
 
@@ -21,44 +24,42 @@ const
21
24
 
22
25
  export let
23
26
  logoUrl = '/'
24
- , logoSrc = `${Utils.imagesRelativePath}logo-quebec-piv-footer.svg`
25
- , logoAlt = 'Gouvernement du Québec'
26
- , logoWidth = '117'
27
- , logoHeight = '35'
27
+ , logoSrc = Utils.imagesRelativePath + '/QUEBEC_couleur.svg'
28
+ , logoSrcDarkTheme = Utils.imagesRelativePath + '/QUEBEC_blanc.svg'
29
+ , logoAlt = lang === 'fr'
30
+ ? 'Logo du gouvernement du Québec'
31
+ : 'Logo of the Quebec government'
28
32
  , copyrightText = '© Gouvernement du Québec, ' + (new Date()).getFullYear()
33
+ , logoWidth = 139
34
+ , logoHeight = 50
29
35
  , copyrightUrl = lang === 'fr'
30
36
  ? 'https://www.quebec.ca/droit-auteur'
31
37
  : 'https://www.quebec.ca/en/copyright'
32
38
  ;
33
-
34
39
  </script>
35
-
36
- <div class="qc-piv-footer qc-component">
37
- <div class="qc-container">
38
- <nav>
39
- <slot/>
40
- </nav>
41
- <div class="logo">
42
- <slot name="logo">
43
- <a href="{logoUrl}">
44
- <img class="logo-mo"
45
- alt="{logoAlt}"
46
- src="{logoSrc}"
47
- width="{logoWidth}"
48
- height="{logoHeight}">
49
- </a>
50
- </slot>
51
- </div>
52
- <span class="copyright">
53
- <slot name="copyright">
54
- <a href="{copyrightUrl}">
55
- {copyrightText}
56
- </a>
57
- </slot>
58
- </span>
59
- </div>
60
-
40
+ <div class="qc-piv-footer qc-container-fluid">
41
+ <slot/>
42
+ <a href="{logoUrl}"
43
+ class="logo"
44
+ style:--logo-width={logoWidth}
45
+ style:--logo-height={logoHeight}
46
+ >
47
+ {#each [
48
+ ['light', logoSrc],
49
+ ['dark', logoSrcDarkTheme]]
50
+ as [theme, src]}
51
+ <img {src}
52
+ alt="{logoAlt}"
53
+ class="qc-{theme}-theme-show"/>
54
+ {/each}
55
+ </a>
56
+ <span class="copyright">
57
+ <slot name="copyright">
58
+ <a href="{copyrightUrl}">
59
+ {copyrightText}
60
+ </a>
61
+ </slot>
62
+ </span>
61
63
  </div>
64
+ <link rel='stylesheet' href='{Utils.cssPath}'>
62
65
 
63
- <link rel='stylesheet'
64
- href='{Utils.cssRelativePath}{Utils.cssFileName}'>
@@ -1,12 +1,20 @@
1
- <svelte:options customElement="qc-to-top" />
1
+ <svelte:options customElement="{{
2
+ tag: 'qc-to-top',
3
+ shadow: 'none',
4
+ props: {
5
+ text: {attribute: 'text', type:'String'},
6
+ }
7
+ }}" />
8
+
2
9
 
3
10
  <script>
4
11
  import { Utils } from "./utils";
12
+ import Icon from "./Icon.svelte";
5
13
 
6
14
  const
7
15
  lang = Utils.getPageLanguage();
8
16
  export let
9
- alt = lang === 'fr'
17
+ text = lang === 'fr'
10
18
  ? "Retour en haut"
11
19
  : "Back to top"
12
20
  , demo = 'false'
@@ -65,17 +73,15 @@
65
73
 
66
74
  <svelte:window on:scroll = {handleScrollUpButton} />
67
75
 
68
- <a href=" "
76
+ <a href="javascript:;"
69
77
  bind:this={toTopElement}
70
- class="qc-to-top qc-icon qc-arrow-up-white"
71
- tabindex="0"
78
+ class="qc-to-top"
72
79
  class:visible
73
80
  on:click|preventDefault={scrollToTop}
74
81
  on:keydown={handleEnterAndSpace}
82
+ tabindex={visible ? 0 : -1}
75
83
  {demo}
76
84
  >
77
- <span>{alt}</span>
78
- </a>
79
-
80
- <link rel='stylesheet'
81
- href='{Utils.cssRelativePath}{Utils.cssFileName}'>
85
+ <Icon type="arrow-up-white" color="background"/>
86
+ <span>{text}</span>
87
+ </a>
@@ -1,10 +1,13 @@
1
1
  export class Utils {
2
2
 
3
3
  static assetsBasePath =
4
- new URL(document.currentScript.src).pathname
5
- .split('/')
6
- .slice(0, -2)
7
- .join('/')
4
+ document
5
+ .currentScript
6
+ .getAttribute('sdg-assets-base-path')
7
+ || new URL(document.currentScript.src).pathname
8
+ .split('/')
9
+ .slice(0, -2)
10
+ .join('/')
8
11
  || '.'
9
12
  static cssRelativePath =
10
13
  `${this.assetsBasePath}/css/`
@@ -17,6 +20,11 @@ export class Utils {
17
20
  .currentScript
18
21
  .getAttribute('sdg-css-filename')
19
22
  || 'qc-sdg.min.css'
23
+ static cssPath =
24
+ document
25
+ .currentScript
26
+ .getAttribute('sdg-css-path')
27
+ || this.cssRelativePath + this.cssFileName
20
28
  static sharedTexts =
21
29
  { openInNewTab :
22
30
  { fr: 'Ce lien s’ouvrira dans un nouvel onglet.'
@@ -31,4 +39,20 @@ export class Utils {
31
39
  static getPageLanguage() {
32
40
  return document.getElementsByTagName("html")[0].getAttribute("lang") || "fr";
33
41
  }
42
+
43
+ static isTruthy(value) {
44
+ if (typeof value === 'boolean') {
45
+ return value;
46
+ }
47
+ if (typeof value === 'string') {
48
+ return value.toLowerCase() === 'true' || !!parseInt(value); // Vérifie si la chaîne est "true" (insensible à la casse)
49
+ }
50
+ if (typeof value === 'number') {
51
+ return !!value; // Vérifie si le nombre est égal à 1
52
+ }
53
+ return false;
54
+ }
55
+
56
+
57
+
34
58
  }
package/src/sdg/qc-sdg.js CHANGED
@@ -1,7 +1,15 @@
1
1
  export * from './components/notice.svelte'
2
- export * from './components/pivHeader.svelte'
2
+ export * from './components/PivHeader/pivHeader.svelte'
3
3
  export * from './components/pivFooter.svelte'
4
4
  export * from './components/alert.svelte'
5
5
  export * from './components/toTop.svelte'
6
- // export * from './doc/components/code.svelte'
7
- import './scss/qc-sdg.scss';
6
+ export * from './components/externalLink.svelte'
7
+ export * from './components/SearchBar/searchBar.svelte'
8
+ export * from './components/SearchInput/SearchInput.svelte'
9
+ export * from './components/Icon.svelte'
10
+ import './scss/qc-sdg.scss' ;
11
+
12
+ const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
13
+ if (isDarkMode) {
14
+ document.documentElement.classList.add('qc-dark-theme')
15
+ }
@@ -0,0 +1,3 @@
1
+ // @use this file to access every variables, function, mixin or %class from Qc SDG
2
+ @forward "lib/gridless-lib";
3
+ @forward "lib/mixins";