qc-trousse-sdg 1.3.2 → 1.4.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.
- package/README.md +5 -1
- package/dist/js/qc-sdg.min.js +1 -1
- package/package.json +3 -3
- package/public/index.html +375 -296
- package/public/js/qc-doc-sdg.js +5043 -1580
- package/public/js/qc-sdg.js +8111 -3685
- package/rollup.config.js +1 -0
- package/src/doc/components/Code.svelte +10 -15
- package/src/doc/components/Exemple.svelte +18 -15
- package/src/doc/components/Switch.svelte +7 -6
- package/src/doc/components/TopNav.svelte +6 -3
- package/src/doc/components/color-doc.svelte +2 -2
- package/src/doc/qc-doc-sdg.js +4 -1
- package/src/sdg/_components.js +10 -9
- package/src/sdg/components/Alert/Alert.svelte +69 -0
- package/src/sdg/components/Alert/AlertWC.svelte +24 -0
- package/src/sdg/components/ExternalLink/ExternalLink.svelte +96 -0
- package/src/sdg/components/ExternalLink/ExternalLinkWC.svelte +15 -0
- package/src/sdg/components/Icon/Icon.svelte +26 -0
- package/src/sdg/components/Icon/IconWC.svelte +20 -0
- package/src/sdg/components/IconButton/IconButton.svelte +30 -0
- package/src/sdg/components/IconButton/IconButtonWC.svelte +19 -0
- package/src/sdg/components/Notice/Notice.svelte +83 -0
- package/src/sdg/components/Notice/NoticeWC.svelte +25 -0
- package/src/sdg/components/PivFooter/PivFooter.svelte +51 -0
- package/src/sdg/components/PivFooter/PivFooterWC.svelte +52 -0
- package/src/sdg/components/PivFooter/_defaultCopyright.svelte +11 -0
- package/src/sdg/components/PivHeader/PivHeader.svelte +144 -0
- package/src/sdg/components/PivHeader/PivHeaderWC.svelte +68 -0
- package/src/sdg/components/PivHeader/_defaultLinks.svelte +24 -0
- package/src/sdg/components/SearchBar/SearchBar.svelte +67 -0
- package/src/sdg/components/SearchBar/SearchBarWC.svelte +17 -0
- package/src/sdg/components/SearchInput/SearchInput.svelte +17 -26
- package/src/sdg/components/SearchInput/SearchInputWC.svelte +16 -0
- package/src/sdg/components/{toTop.svelte → ToTop/ToTop.svelte} +31 -38
- package/src/sdg/components/ToTop/ToTopWC.svelte +16 -0
- package/src/sdg/components/utils.js +1 -1
- package/src/sdg/components/Button/IconButton.svelte +0 -29
- package/src/sdg/components/Icon.svelte +0 -39
- package/src/sdg/components/PivHeader/pivHeader.svelte +0 -158
- package/src/sdg/components/SearchBar/searchBar.svelte +0 -87
- package/src/sdg/components/alert.svelte +0 -88
- package/src/sdg/components/componentWrapper.js +0 -24
- package/src/sdg/components/externalLink.svelte +0 -92
- package/src/sdg/components/notice.svelte +0 -83
- package/src/sdg/components/pivFooter.svelte +0 -65
package/rollup.config.js
CHANGED
|
@@ -11,22 +11,17 @@
|
|
|
11
11
|
<script>
|
|
12
12
|
|
|
13
13
|
import {HighlightJS} from "highlight.js"
|
|
14
|
-
// import 'highlight.js/styles/default.css';
|
|
15
14
|
import pretty from "pretty";
|
|
16
|
-
import { onMount } from "svelte";
|
|
17
|
-
import { Utils } from "../../sdg/components/utils"
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
targetId = ''
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
;
|
|
16
|
+
let {
|
|
17
|
+
targetId = '',
|
|
18
|
+
rawCode = '',
|
|
19
|
+
language = 'html',
|
|
20
|
+
outerHTML = false
|
|
21
|
+
} = $props();
|
|
25
22
|
|
|
26
|
-
let
|
|
27
|
-
|
|
28
|
-
, prettyCode
|
|
29
|
-
;
|
|
23
|
+
let hlCode = $state();
|
|
24
|
+
let prettyCode = $state();
|
|
30
25
|
|
|
31
26
|
function copy() {
|
|
32
27
|
navigator.clipboard.writeText(prettyCode);
|
|
@@ -48,14 +43,14 @@
|
|
|
48
43
|
hlCode = HighlightJS.highlight(prettyCode, {language:language}).value;
|
|
49
44
|
}
|
|
50
45
|
|
|
51
|
-
|
|
46
|
+
$effect(() => updateHLCode(rawCode, targetId));
|
|
52
47
|
|
|
53
48
|
</script>
|
|
54
49
|
|
|
55
50
|
<pre
|
|
56
51
|
><code class="hljs"
|
|
57
52
|
><button class="btn btn-sm btn-primary"
|
|
58
|
-
|
|
53
|
+
onclick={copy}>
|
|
59
54
|
<span class="copy">copier</span>
|
|
60
55
|
<span class="copied">copié !</span>
|
|
61
56
|
</button
|
|
@@ -11,24 +11,27 @@
|
|
|
11
11
|
<script>
|
|
12
12
|
import Code from "./Code.svelte";
|
|
13
13
|
import {onMount} from "svelte";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
caption = "SVP fournir une description",
|
|
17
|
+
codeTargetId,
|
|
18
|
+
hideCode = false,
|
|
19
|
+
rawCode,
|
|
20
|
+
...restProps
|
|
21
|
+
} = $props();
|
|
22
|
+
|
|
23
|
+
let exempleCode = $state();
|
|
24
|
+
let figure = $state();
|
|
25
|
+
let rootElement = $state();
|
|
26
|
+
let exempleArea = $state();
|
|
27
|
+
let figCaption = $state();
|
|
28
|
+
|
|
25
29
|
onMount(() => {
|
|
26
30
|
rootElement.parentElement.childNodes.forEach(node => {
|
|
27
|
-
if (node.nodeType
|
|
31
|
+
if (node.nodeType === 3) {
|
|
28
32
|
return;
|
|
29
33
|
}
|
|
30
|
-
if (node
|
|
31
|
-
// let detach = rootElement.removeChild(node)
|
|
34
|
+
if (node !== rootElement) {
|
|
32
35
|
exempleArea.appendChild(node)
|
|
33
36
|
}
|
|
34
37
|
exempleCode = rawCode
|
|
@@ -42,7 +45,7 @@
|
|
|
42
45
|
<div bind:this={rootElement}
|
|
43
46
|
class="exemple-area"
|
|
44
47
|
>
|
|
45
|
-
<figure {
|
|
48
|
+
<figure {...restProps}
|
|
46
49
|
bind:this={figure}
|
|
47
50
|
>
|
|
48
51
|
<div bind:this={exempleArea}
|
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
shadow:'none'
|
|
4
4
|
}}" />
|
|
5
5
|
<script>
|
|
6
|
-
|
|
7
|
-
value=false,
|
|
8
|
-
name='switch',
|
|
6
|
+
let {
|
|
7
|
+
value = $bindable(false),
|
|
8
|
+
name = 'switch',
|
|
9
9
|
color = {
|
|
10
10
|
unchecked: 'grey-light',
|
|
11
11
|
checked: 'blue-regular',
|
|
12
12
|
slider: 'background'
|
|
13
|
-
}
|
|
14
|
-
|
|
13
|
+
},
|
|
14
|
+
...rest
|
|
15
|
+
} = $props();
|
|
15
16
|
|
|
16
17
|
</script>
|
|
17
18
|
<div class="switch"
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
{name}
|
|
26
27
|
bind:checked={value}
|
|
27
28
|
aria-checked={value}
|
|
28
|
-
{
|
|
29
|
+
{...rest}
|
|
29
30
|
/>
|
|
30
31
|
<span class="slider round" ></span>
|
|
31
32
|
</div>
|
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
}}" />
|
|
8
8
|
<script>
|
|
9
9
|
import Switch from "./Switch.svelte";
|
|
10
|
-
let value = localStorage.getItem('dark-theme') === "true";
|
|
10
|
+
let value = $state(localStorage.getItem('dark-theme') === "true");
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
$effect(() => {
|
|
13
|
+
document.documentElement.classList.toggle('qc-dark-theme', value);
|
|
14
|
+
localStorage.setItem('dark-theme', value);
|
|
15
|
+
});
|
|
14
16
|
</script>
|
|
17
|
+
|
|
15
18
|
<div role="complementary">
|
|
16
19
|
<div class="qc-container top-nav">
|
|
17
20
|
<div class="switch-control">
|
package/src/doc/qc-doc-sdg.js
CHANGED
package/src/sdg/_components.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export * from './components/
|
|
2
|
-
export * from './components/PivHeader/
|
|
3
|
-
export * from './components/
|
|
4
|
-
export * from './components/
|
|
5
|
-
export * from './components/
|
|
6
|
-
export * from './components/
|
|
7
|
-
export * from './components/SearchBar/
|
|
8
|
-
export * from './components/SearchInput/
|
|
9
|
-
export * from './components/Icon.svelte'
|
|
1
|
+
export * from './components/Notice/NoticeWC.svelte'
|
|
2
|
+
export * from './components/PivHeader/PivHeaderWC.svelte'
|
|
3
|
+
export * from './components/PivFooter/PivFooterWC.svelte'
|
|
4
|
+
export * from './components/Alert/AlertWC.svelte'
|
|
5
|
+
export * from './components/ToTop/toTopWC.svelte'
|
|
6
|
+
export * from './components/ExternalLink/ExternalLinkWC.svelte'
|
|
7
|
+
export * from './components/SearchBar/SearchBarWC.svelte'
|
|
8
|
+
export * from './components/SearchInput/SearchInputWC.svelte'
|
|
9
|
+
export * from './components/Icon/IconWC.svelte'
|
|
10
|
+
export * from './components/IconButton/IconButtonWC.svelte'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import {Utils} from "../utils";
|
|
3
|
+
import Icon from "../Icon/Icon.svelte";
|
|
4
|
+
import IconButton from "../IconButton/IconButton.svelte";
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
type = "general",
|
|
8
|
+
maskable = "",
|
|
9
|
+
content = "",
|
|
10
|
+
hide = "false",
|
|
11
|
+
fullWidth = "false",
|
|
12
|
+
slotContent,
|
|
13
|
+
} = $props();
|
|
14
|
+
|
|
15
|
+
const language = Utils.getPageLanguage();
|
|
16
|
+
|
|
17
|
+
const typeClass = (type !== "") ? type : 'general';
|
|
18
|
+
const closeLabel = language === 'fr' ? "Fermer l’alerte" : "Close l’alerte";
|
|
19
|
+
const warningLabel = language === 'fr' ? "Information d'importance élevée" : "Information of high importance";
|
|
20
|
+
const generalLabel = language === 'fr' ? "Information importante" : "Important information";
|
|
21
|
+
|
|
22
|
+
const label = type === 'general' ? generalLabel : warningLabel;
|
|
23
|
+
|
|
24
|
+
let rootElement = $state(null);
|
|
25
|
+
|
|
26
|
+
let containerClass = "qc-container" + (fullWidth === 'true' ? '-fluid' : '');
|
|
27
|
+
|
|
28
|
+
function hideAlert() {
|
|
29
|
+
hide = "true";
|
|
30
|
+
rootElement.dispatchEvent(
|
|
31
|
+
new CustomEvent('qc.alert.hide', {
|
|
32
|
+
bubbles: true,
|
|
33
|
+
composed: true
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
{#if !Utils.isTruthy(hide)}
|
|
40
|
+
<div bind:this={rootElement}
|
|
41
|
+
class="qc-general-alert {typeClass}"
|
|
42
|
+
role="alert">
|
|
43
|
+
<div class={containerClass}>
|
|
44
|
+
<div class="qc-general-alert-elements">
|
|
45
|
+
<Icon type={type === 'warning' ? 'warning' : 'information'}
|
|
46
|
+
color={type === 'general' ? 'blue-piv' : 'yellow-dark'}
|
|
47
|
+
size="nm"
|
|
48
|
+
label={label}
|
|
49
|
+
/>
|
|
50
|
+
<div class="qc-alert-content">
|
|
51
|
+
{@html content}
|
|
52
|
+
{@html slotContent}
|
|
53
|
+
</div>
|
|
54
|
+
{#if Utils.isTruthy(maskable)}
|
|
55
|
+
<IconButton aria-label={closeLabel}
|
|
56
|
+
onclick={hideAlert}
|
|
57
|
+
size="nm"
|
|
58
|
+
icon="clear-input"
|
|
59
|
+
iconSize="sm"
|
|
60
|
+
iconColor="text-primary"
|
|
61
|
+
/>
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
{/if}
|
|
67
|
+
|
|
68
|
+
<link rel='stylesheet'
|
|
69
|
+
href='{Utils.cssPath}'>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<svelte:options customElement="{{
|
|
2
|
+
tag:'qc-alert',
|
|
3
|
+
reflect: true,
|
|
4
|
+
props: {
|
|
5
|
+
type : {attribute: 'type'},
|
|
6
|
+
maskable : {attribute: 'maskable'},
|
|
7
|
+
fullWidth : {attribute: 'full-width'},
|
|
8
|
+
content: {attribute: 'content'},
|
|
9
|
+
hide: {attribute: 'hide'},
|
|
10
|
+
}
|
|
11
|
+
}}"/>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
|
|
15
|
+
import Alert from "./Alert.svelte";
|
|
16
|
+
|
|
17
|
+
const props = $props();
|
|
18
|
+
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<Alert
|
|
22
|
+
{...props}
|
|
23
|
+
slotContent = {`<slot />`}
|
|
24
|
+
/>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import {Utils} from "../utils";
|
|
3
|
+
import {onMount} from "svelte";
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
externalIconAlt = Utils.getPageLanguage() === 'fr'
|
|
7
|
+
? "Ce lien dirige vers un autre site."
|
|
8
|
+
: "This link directs to another site."
|
|
9
|
+
} = $props();
|
|
10
|
+
|
|
11
|
+
let imgElement = $state();
|
|
12
|
+
|
|
13
|
+
function createVisibleNodesTreeWalker() {
|
|
14
|
+
return document.createTreeWalker(
|
|
15
|
+
imgElement.parentElement,
|
|
16
|
+
NodeFilter.SHOW_ALL,
|
|
17
|
+
{
|
|
18
|
+
acceptNode: node => {
|
|
19
|
+
if (node instanceof Element) {
|
|
20
|
+
if (node.hasAttribute('hidden')) {
|
|
21
|
+
return NodeFilter.FILTER_REJECT;
|
|
22
|
+
}
|
|
23
|
+
const style = window.getComputedStyle(node);
|
|
24
|
+
// Si l'élément est masqué par CSS (display ou visibility), on l'ignore
|
|
25
|
+
if (style.display === 'none'
|
|
26
|
+
|| style.visibility === 'hidden'
|
|
27
|
+
|| style.position === 'absolute') {
|
|
28
|
+
return NodeFilter.FILTER_REJECT;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!node instanceof Text) {
|
|
32
|
+
return NodeFilter.FILTER_SKIP;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Ignore les nœuds vides
|
|
36
|
+
if (!/\S/.test(node.textContent)) {
|
|
37
|
+
return NodeFilter.FILTER_SKIP;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onMount(() => {
|
|
47
|
+
imgElement.parentElement.querySelectorAll('a').forEach(link => {
|
|
48
|
+
|
|
49
|
+
// Crée un TreeWalker pour parcourir uniquement les nœuds texte visibles
|
|
50
|
+
const walker = createVisibleNodesTreeWalker();
|
|
51
|
+
|
|
52
|
+
let lastTextNode = null;
|
|
53
|
+
while (walker.nextNode()) {
|
|
54
|
+
lastTextNode = walker.currentNode;
|
|
55
|
+
}
|
|
56
|
+
// S'il n'y a pas de nœud texte visible, on ne fait rien
|
|
57
|
+
if (!lastTextNode) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
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 match = text.match(/^([\s\S]*\s)?(\S+)\s*$/m);
|
|
65
|
+
if (!match) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const prefix = match[1] || "";
|
|
70
|
+
const lastWord = match[2];
|
|
71
|
+
|
|
72
|
+
// Crée un span avec white-space: nowrap pour empêcher le saut de ligne de l'image de lien externe
|
|
73
|
+
const span = document.createElement('span');
|
|
74
|
+
span.classList.add('img-wrap')
|
|
75
|
+
span.innerHTML = `${lastWord}`;
|
|
76
|
+
span.appendChild(imgElement)
|
|
77
|
+
|
|
78
|
+
// Met à jour le nœud texte : on garde le préfixe et on insère le span après
|
|
79
|
+
if (prefix) {
|
|
80
|
+
lastTextNode.textContent = prefix;
|
|
81
|
+
lastTextNode.parentNode.insertBefore(span, lastTextNode.nextSibling);
|
|
82
|
+
} else {
|
|
83
|
+
lastTextNode.parentNode.replaceChild(span, lastTextNode);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<span bind:this={imgElement}
|
|
90
|
+
role="img"
|
|
91
|
+
class="qc-ext-link-img"
|
|
92
|
+
aria-label={externalIconAlt}>
|
|
93
|
+
</span>
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
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 ExternalLink from "./ExternalLink.svelte";
|
|
11
|
+
|
|
12
|
+
const props = $props();
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<ExternalLink {...props} />
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
let {
|
|
3
|
+
type,
|
|
4
|
+
label,
|
|
5
|
+
size = 'md',
|
|
6
|
+
color = 'text-primary',
|
|
7
|
+
width='auto',
|
|
8
|
+
height='auto',
|
|
9
|
+
...rest
|
|
10
|
+
} = $props();
|
|
11
|
+
|
|
12
|
+
let attributes = $derived(width === 'auto' ? { 'data-img-size': size } : {});
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<div role="img"
|
|
16
|
+
class="qc-icon"
|
|
17
|
+
aria-label={label}
|
|
18
|
+
style="--img-color:var(--qc-color-{color});
|
|
19
|
+
--img-width:{width};
|
|
20
|
+
--img-height:{height};
|
|
21
|
+
"
|
|
22
|
+
data-img-type={type}
|
|
23
|
+
{...attributes}
|
|
24
|
+
{...rest}
|
|
25
|
+
>
|
|
26
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<svelte:options customElement="{{
|
|
2
|
+
tag: 'qc-icon',
|
|
3
|
+
shadow: 'none',
|
|
4
|
+
props: {
|
|
5
|
+
type : {attribute: 'icon'},
|
|
6
|
+
label: {attribute: 'label'},
|
|
7
|
+
color: {attribute: 'color'},
|
|
8
|
+
size: {attribute: 'size'},
|
|
9
|
+
width: {attribute: 'width'},
|
|
10
|
+
height: {attribute: 'height'}
|
|
11
|
+
}
|
|
12
|
+
}}" />
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import Icon from "./Icon.svelte";
|
|
16
|
+
|
|
17
|
+
const props = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<Icon {...props} />
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Icon from "../Icon/Icon.svelte";
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
size = 'xl',
|
|
6
|
+
label,
|
|
7
|
+
icon,
|
|
8
|
+
iconSize,
|
|
9
|
+
iconColor,
|
|
10
|
+
class: className = '',
|
|
11
|
+
...rest
|
|
12
|
+
} = $props();
|
|
13
|
+
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<button
|
|
17
|
+
data-button-size={size}
|
|
18
|
+
class={`qc-icon-button ${className}`}
|
|
19
|
+
{...rest}
|
|
20
|
+
>
|
|
21
|
+
{#if icon}
|
|
22
|
+
<Icon type={icon}
|
|
23
|
+
size={iconSize}
|
|
24
|
+
color={iconColor}
|
|
25
|
+
aria-hidden="true"
|
|
26
|
+
label={label}
|
|
27
|
+
/>
|
|
28
|
+
{/if}
|
|
29
|
+
</button>
|
|
30
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<svelte:options customElement={{
|
|
2
|
+
tag: 'qc-icon-button',
|
|
3
|
+
shadow: 'none',
|
|
4
|
+
props: {
|
|
5
|
+
size: { attribute: 'size' },
|
|
6
|
+
label: { attribute: 'label' },
|
|
7
|
+
icon: { attribute: 'icon' },
|
|
8
|
+
iconSize: { attribute: 'icon-size' },
|
|
9
|
+
iconColor: { attribute: 'icon-color' }
|
|
10
|
+
}
|
|
11
|
+
}} />
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import IconButton from './IconButton.svelte';
|
|
15
|
+
|
|
16
|
+
const props = $props();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<IconButton {...props} />
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Utils } from "../utils"
|
|
3
|
+
import Icon from "../Icon/Icon.svelte";
|
|
4
|
+
|
|
5
|
+
const isFr = Utils.getPageLanguage() === 'fr';
|
|
6
|
+
const defaultHeader = 'h2';
|
|
7
|
+
const defaultType = 'information';
|
|
8
|
+
const typesDescriptions = {
|
|
9
|
+
'advice': isFr ? "Avis conseil" : "Advisory notice",
|
|
10
|
+
'note': isFr ? "Avis explicatif" : "Explanatory notice",
|
|
11
|
+
'information': isFr ? "Avis général" : "General notice",
|
|
12
|
+
'warning': isFr ? "Avis d’avertissement" : "Warning notice",
|
|
13
|
+
'success': isFr ? "Avis de réussite" : "Success notice",
|
|
14
|
+
'error': isFr ? "Avis d’erreur" : "Error notice"
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
let {
|
|
18
|
+
title = "",
|
|
19
|
+
type = defaultType,
|
|
20
|
+
content = "",
|
|
21
|
+
header = defaultHeader,
|
|
22
|
+
icon,
|
|
23
|
+
slotContent
|
|
24
|
+
} = $props();
|
|
25
|
+
|
|
26
|
+
const types = Object.keys(typesDescriptions);
|
|
27
|
+
|
|
28
|
+
const usedType = types.includes(type) ? type : defaultType;
|
|
29
|
+
const usedHeader = header.match(/h[1-6]/) ? header : defaultHeader;
|
|
30
|
+
const role = usedType === "success" ? "status" : (usedType === "error" ? "alert" : null);
|
|
31
|
+
|
|
32
|
+
let noticeElement = $state(null);
|
|
33
|
+
$effect(() => {
|
|
34
|
+
if (role && noticeElement) {
|
|
35
|
+
const tempNodes = Array.from(noticeElement.childNodes);
|
|
36
|
+
noticeElement.innerHTML = "";
|
|
37
|
+
|
|
38
|
+
// Réinsère le contenu pour qu'il soit détecté par le lecteur d'écran.
|
|
39
|
+
tempNodes.forEach(node => noticeElement.appendChild(node));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const shouldUseIcon = usedType === "advice" || usedType === "note";
|
|
44
|
+
|
|
45
|
+
// Si le type est "advice" ou "note", on force "neutral" (le gris), sinon on garde le type normal
|
|
46
|
+
const computedType = shouldUseIcon ? "neutral" : usedType;
|
|
47
|
+
const iconType = shouldUseIcon ? (icon ?? "note") : usedType;
|
|
48
|
+
const iconLabel = typesDescriptions[type] ?? typesDescriptions['information'];
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<!-- 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). -->
|
|
52
|
+
<!--Le warning `Svelte: noninteractive element cannot have nonnegative tabIndex value`
|
|
53
|
+
associe a tabindex="0" doit etre ignore pour qu'on puisse focus sur le composant sans
|
|
54
|
+
le denaturaliser.-->
|
|
55
|
+
|
|
56
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
57
|
+
<div class="qc-component qc-notice qc-{computedType}"
|
|
58
|
+
tabindex="0"
|
|
59
|
+
>
|
|
60
|
+
<div class="icon-container">
|
|
61
|
+
<div class="qc-icon">
|
|
62
|
+
<Icon type={iconType}
|
|
63
|
+
label={iconLabel}
|
|
64
|
+
size="nm"
|
|
65
|
+
/>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div class="content-container">
|
|
70
|
+
<div class="content" {role} bind:this={noticeElement}>
|
|
71
|
+
{#if title && title !== ""}
|
|
72
|
+
<svelte:element this={usedHeader}>
|
|
73
|
+
{@html title}
|
|
74
|
+
</svelte:element>
|
|
75
|
+
{/if}
|
|
76
|
+
|
|
77
|
+
{@html content}
|
|
78
|
+
|
|
79
|
+
{@render slotContent?.()}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
<link rel='stylesheet' href='{Utils.cssPath}'>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<svelte:options customElement={{
|
|
2
|
+
tag: 'qc-notice',
|
|
3
|
+
props: {
|
|
4
|
+
title: { attribute: 'title', type: 'String' },
|
|
5
|
+
type: { attribute: 'type', type: 'String' },
|
|
6
|
+
content: { attribute: 'content', type: 'String' },
|
|
7
|
+
header: { attribute: 'header', type: 'String' },
|
|
8
|
+
icon: { attribute: 'icon', type: 'String' }
|
|
9
|
+
}
|
|
10
|
+
}} />
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
import Notice from './Notice.svelte';
|
|
14
|
+
|
|
15
|
+
const props = $props();
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
<Notice
|
|
20
|
+
{...props}
|
|
21
|
+
>
|
|
22
|
+
{#snippet slotContent()}
|
|
23
|
+
<slot />
|
|
24
|
+
{/snippet}
|
|
25
|
+
</Notice>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Utils } from "../utils"
|
|
3
|
+
import DefaultCopyright from "./_defaultCopyright.svelte";
|
|
4
|
+
const lang = Utils.getPageLanguage();
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
logoUrl = '/',
|
|
8
|
+
logoSrc = Utils.imagesRelativePath + '/QUEBEC_couleur.svg',
|
|
9
|
+
logoSrcDarkTheme = Utils.imagesRelativePath + '/QUEBEC_blanc.svg',
|
|
10
|
+
logoAlt = lang === 'fr' ? 'Logo du gouvernement du Québec' : 'Logo of the Quebec government',
|
|
11
|
+
copyrightText,
|
|
12
|
+
logoWidth = 139,
|
|
13
|
+
logoHeight = 50,
|
|
14
|
+
copyrightUrl,
|
|
15
|
+
mainSlot,
|
|
16
|
+
copyrightSlot
|
|
17
|
+
} = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<div class="qc-piv-footer qc-container-fluid">
|
|
21
|
+
{#if mainSlot}
|
|
22
|
+
{@render mainSlot()}
|
|
23
|
+
{/if}
|
|
24
|
+
|
|
25
|
+
<a href="{logoUrl}"
|
|
26
|
+
class="logo"
|
|
27
|
+
style:--logo-width={logoWidth}
|
|
28
|
+
style:--logo-height={logoHeight}
|
|
29
|
+
>
|
|
30
|
+
{#each [
|
|
31
|
+
['light', logoSrc],
|
|
32
|
+
['dark', logoSrcDarkTheme]]
|
|
33
|
+
as [theme, src]}
|
|
34
|
+
<img {src}
|
|
35
|
+
alt="{logoAlt}"
|
|
36
|
+
class="qc-{theme}-theme-show"
|
|
37
|
+
/>
|
|
38
|
+
{/each}
|
|
39
|
+
</a>
|
|
40
|
+
|
|
41
|
+
<span class="copyright">
|
|
42
|
+
{#if copyrightSlot}
|
|
43
|
+
{@render copyrightSlot()}
|
|
44
|
+
{:else}
|
|
45
|
+
<DefaultCopyright {copyrightText} {copyrightUrl} />
|
|
46
|
+
{/if}
|
|
47
|
+
</span>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<link rel='stylesheet' href='{Utils.cssPath}'>
|
|
51
|
+
|