ep-lib-ts 1.0.46 → 1.0.48
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/dist/BgAudio-kLycvFEF.js +4 -0
- package/dist/Details-Op3Zkhcg.js +4 -0
- package/dist/DisplayBox-DGsKoxmr.js +4 -0
- package/dist/{Ep360Image-CQJBPImD.js → Ep360Image-DHK_IWTi.js} +1 -1
- package/dist/{Ep360Video-CL_7mOiQ.js → Ep360Video-C4PekHTc.js} +1 -1
- package/dist/EpAlert-aWrJokXa.js +4 -0
- package/dist/EpAudio-DGFoC0Go.js +4 -0
- package/dist/EpAvatar-1yU-OXsu.js +4 -0
- package/dist/EpBadge-BlIhFCIg.js +4 -0
- package/dist/EpBarChart-KgYdXvMq.js +4 -0
- package/dist/EpBtn-S1mCeeV7.js +4 -0
- package/dist/EpCard-COy2GODb.js +4 -0
- package/dist/EpCardLink-SBppyTrI.js +4 -0
- package/dist/EpChip-CNRaxrjP.js +4 -0
- package/dist/EpCodeblock-NyXHH5gD.js +4 -0
- package/dist/EpConclusion-CUWiK_nt.js +4 -0
- package/dist/EpContentSlider-mpqkd2T2.js +4 -0
- package/dist/{EpDarkmode-DyUrMSO5.js → EpDarkmode-C5NMN4h2.js} +1 -1
- package/dist/EpDescription-Dewh9Bmr.js +4 -0
- package/dist/EpDivider-C_cgaXNK.js +4 -0
- package/dist/EpDocument-CmN-KUVt.js +4 -0
- package/dist/{EpDraggable-CTWqRQzE.js → EpDraggable-BwpIpRyf.js} +74 -74
- package/dist/EpEdu-BRXEfH5H.js +4 -0
- package/dist/EpFlex-UUXOmWtZ.js +4 -0
- package/dist/EpFunnelChart-DgkcR1ON.js +4 -0
- package/dist/EpHeader-DeiRUZRl.js +4 -0
- package/dist/EpHover-BKK7j48J.js +4 -0
- package/dist/EpHoverCard-6ZKNpNBq.js +4 -0
- package/dist/EpIcon-C3jjducH.js +4 -0
- package/dist/EpIframe-CoaO5gb_.js +4 -0
- package/dist/EpImg-iypQu6WK.js +4 -0
- package/dist/EpImgCarousel-vagns6kd.js +4 -0
- package/dist/{EpInput-CGnN-piP.js → EpInput-uDeg10dD.js} +30 -30
- package/dist/EpInstructions-C2JYulUa.js +4 -0
- package/dist/EpIntroduction-BJXDxfYV.js +4 -0
- package/dist/EpLineChart-BVlswUIa.js +4 -0
- package/dist/EpLink-DPR3gH7f.js +4 -0
- package/dist/EpLinkVersion-DqQvfQQT.js +4 -0
- package/dist/{EpList-C8uaLum6.js → EpList-BI7oPTHl.js} +1 -1
- package/dist/EpModal-DN-QQzrQ.js +4 -0
- package/dist/{EpNothing-DxfGfasN.js → EpNothing-z596jG9D.js} +1 -1
- package/dist/EpObjective-sNcUzMGj.js +4 -0
- package/dist/EpPieChart-CCgGmemH.js +4 -0
- package/dist/EpQuestion-DJ-1vSS6.js +4 -0
- package/dist/EpQuote-BWRF6A-L.js +4 -0
- package/dist/EpRadio-BLbK_ijo.js +4 -0
- package/dist/EpRadioSummative-BtiAeyHR.js +4 -0
- package/dist/EpReading-C78Icl4m.js +4 -0
- package/dist/EpResource-C_JQvg2g.js +4 -0
- package/dist/EpScope-D1e7l9RQ.js +4 -0
- package/dist/EpSection-C9VobPvp.js +4 -0
- package/dist/EpSectionCols-D9DqSfNG.js +4 -0
- package/dist/EpSkeleton-Cc3nfQlv.js +4 -0
- package/dist/EpSoftware-Bga9b4WM.js +4 -0
- package/dist/EpSpecificObjective-C9MHA7ez.js +4 -0
- package/dist/EpSpinner-BOpURQEs.js +4 -0
- package/dist/EpStackedList-BdIF2Obj.js +4 -0
- package/dist/EpSummativeTable-BTLrKIHA.js +4 -0
- package/dist/EpSvg-CJfC1DMY.js +4 -0
- package/dist/EpSvgShow-SnjMv4b2.js +4 -0
- package/dist/EpTable--hx3As1M.js +4 -0
- package/dist/EpTerm-l4uolPHU.js +4 -0
- package/dist/EpText-Dvi-oAJe.js +4 -0
- package/dist/EpTimeLine-BeRMD8rW.js +4 -0
- package/dist/EpVideo-D4DR93ep.js +4 -0
- package/dist/EpVideoPanopto-CVjjy9Nn.js +4 -0
- package/dist/EpWordDef-DRBqhyxR.js +4 -0
- package/dist/TextMedia-LKMaVja3.js +4 -0
- package/dist/components/educationals/EpBranchingScenario.vue.d.ts +43 -5
- package/dist/components/educationals/EpDocument.vue.d.ts +44 -0
- package/dist/components/interactions/EpSvgShow.vue.d.ts +0 -1
- package/dist/components/medias/EpHierarchy.vue.d.ts +51 -0
- package/dist/components/medias/EpSoftware.vue.d.ts +0 -1
- package/dist/components/tools/Details.vue.d.ts +36 -0
- package/dist/components/tools/TextMedia.vue.d.ts +25 -0
- package/dist/ep-lib-ts.js +44 -40
- package/dist/ep-lib-ts.umd.cjs +212 -212
- package/dist/{index-IdtPmXeP.js → index-CO05CQPt.js} +461 -514
- package/dist/{index-D5QYJLNE.js → index-DH1gIdAA.js} +1 -1
- package/dist/{index-FmXc2ivj.js → index-DeiLPw0s.js} +10876 -7941
- package/dist/index.d.ts +5 -1
- package/dist/{prism-D-x8E1YK.js → prism-BvbRGWPO.js} +1 -1
- package/dist/style.css +1 -1
- package/dist/{three.module-CWLs6nMo.js → three.module-B-oqC8Xk.js} +1 -1
- package/dist/types/Component.d.ts +7 -0
- package/dist/types/Hierarchy.d.ts +14 -0
- package/package.json +11 -1
- package/src/components/basics/EpBtn.vue +1 -1
- package/src/components/educationals/EpBranchingScenario.vue +202 -124
- package/src/components/educationals/EpDocument.vue +92 -0
- package/src/components/interactions/EpContentSlider.vue +1 -1
- package/src/components/interactions/EpDraggable.vue +4 -4
- package/src/components/interactions/EpSvgShow.vue +66 -66
- package/src/components/medias/EpHierarchy.vue +345 -0
- package/src/components/medias/EpSoftware.vue +1 -2
- package/src/components/tools/Details.vue +46 -0
- package/src/components/tools/TextMedia.vue +34 -0
- package/dist/BgAudio-ryf2FIxF.js +0 -4
- package/dist/DisplayBox-ky90shjr.js +0 -4
- package/dist/EpAlert-BUiXiWRL.js +0 -4
- package/dist/EpAudio-CkZrkt3Z.js +0 -4
- package/dist/EpAvatar-2ZL5g8-2.js +0 -4
- package/dist/EpBadge-vOdZrc0e.js +0 -4
- package/dist/EpBarChart-CUUaOMsS.js +0 -4
- package/dist/EpBranchingScenario-DT2VQz7o.js +0 -160
- package/dist/EpBtn-DD0ykcYq.js +0 -4
- package/dist/EpCard-Qgkskboo.js +0 -4
- package/dist/EpCardLink-BfTUOLcA.js +0 -4
- package/dist/EpChip-P7j6l0PH.js +0 -4
- package/dist/EpCodeblock-DpzMd_h0.js +0 -4
- package/dist/EpConclusion-BRBOGFVk.js +0 -4
- package/dist/EpContentSlider-KFhPqR1h.js +0 -4
- package/dist/EpDescription-CcdsFWCf.js +0 -4
- package/dist/EpDivider-C30UAjvv.js +0 -4
- package/dist/EpEdu-CApC3SiS.js +0 -4
- package/dist/EpFlex-Dgc5dinh.js +0 -4
- package/dist/EpFunnelChart-Xm34GDMu.js +0 -4
- package/dist/EpHeader-DSKKm621.js +0 -4
- package/dist/EpHover-KHdqQJ6y.js +0 -4
- package/dist/EpHoverCard-Ccl2Un2s.js +0 -4
- package/dist/EpIcon-Eezd-EUx.js +0 -4
- package/dist/EpIframe-CmEsIYyW.js +0 -4
- package/dist/EpImg-BV_rS7v3.js +0 -4
- package/dist/EpImgCarousel-BHade9dP.js +0 -4
- package/dist/EpInstructions-A6ajkYEJ.js +0 -4
- package/dist/EpIntroduction-BY39wrQW.js +0 -4
- package/dist/EpLineChart-DQNIlO9r.js +0 -4
- package/dist/EpLink-BdxmUlWG.js +0 -4
- package/dist/EpLinkVersion-BAsA6tzp.js +0 -4
- package/dist/EpModal-DIEKXVnQ.js +0 -4
- package/dist/EpObjective-DwnP_7Zm.js +0 -4
- package/dist/EpPieChart-DmcML2d-.js +0 -4
- package/dist/EpQuestion-D7-nzMHE.js +0 -4
- package/dist/EpQuote-Cb5Ty6Ec.js +0 -4
- package/dist/EpRadio-9V6iAh4n.js +0 -4
- package/dist/EpRadioSummative-BL2YhCK3.js +0 -4
- package/dist/EpReading-DTWjzj6l.js +0 -4
- package/dist/EpResource-ZMfXpSqf.js +0 -4
- package/dist/EpScope-1aCF0beo.js +0 -4
- package/dist/EpSection-C-GaZN4R.js +0 -4
- package/dist/EpSectionCols-ap4Z5x7P.js +0 -4
- package/dist/EpSkeleton-DQUHmKio.js +0 -4
- package/dist/EpSoftware-DdF8BdqQ.js +0 -4
- package/dist/EpSpecificObjective-44uQGH3u.js +0 -4
- package/dist/EpSpinner-DHU8EZRf.js +0 -4
- package/dist/EpStackedList-BBGlTBx6.js +0 -4
- package/dist/EpSummativeTable-Cz4gcxHT.js +0 -4
- package/dist/EpSvg-Dk_q0cGB.js +0 -4
- package/dist/EpSvgShow-Cb_Y5UGq.js +0 -54
- package/dist/EpTable-Cg3-lRZY.js +0 -4
- package/dist/EpTerm-CRkB0QyE.js +0 -4
- package/dist/EpText-Dj93fveo.js +0 -4
- package/dist/EpTimeLine-Cit4tc3F.js +0 -4
- package/dist/EpVideo-1obD7bUC.js +0 -4
- package/dist/EpVideoPanopto-DzkzWyOF.js +0 -4
- package/dist/EpWordDef-DIjwoqzN.js +0 -4
|
@@ -39,7 +39,7 @@ const updateSize = () => {
|
|
|
39
39
|
const rect = myImage.value.getBoundingClientRect();
|
|
40
40
|
actualRect.value = { width: rect.width, height: rect.height };
|
|
41
41
|
|
|
42
|
-
console.log('Image size updated. Width:', actualRect.value.width, 'Height:', actualRect.value.height);
|
|
42
|
+
//console.log('Image size updated. Width:', actualRect.value.width, 'Height:', actualRect.value.height);
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
|
|
@@ -56,7 +56,7 @@ const handleImageLoad = (event: any) => {
|
|
|
56
56
|
originalWidth.value = event.target.naturalWidth;
|
|
57
57
|
originalHeight.value = event.target.naturalHeight;
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
// console.log('Image loaded. Width:', originalWidth.value, 'Height:', originalHeight.value);
|
|
60
60
|
|
|
61
61
|
updateSize();
|
|
62
62
|
}
|
|
@@ -93,7 +93,7 @@ const choices = ref<Choice[]>( props.sockets.map((s) => {
|
|
|
93
93
|
|
|
94
94
|
// Manage drag and drop
|
|
95
95
|
const onAdd = (event: any, index: number) => {
|
|
96
|
-
|
|
96
|
+
// console.log(event.clone);
|
|
97
97
|
|
|
98
98
|
// Retirer l'élément de la liste des réponses disponibles
|
|
99
99
|
availableAnswers.value = availableAnswers.value.filter(item => item.name !== event.clone.name);
|
|
@@ -101,7 +101,7 @@ const onAdd = (event: any, index: number) => {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
const onRemove = (event: any, index: number) => {
|
|
104
|
-
|
|
104
|
+
// console.log(event.clone);
|
|
105
105
|
|
|
106
106
|
choices.value[index].choice = [];
|
|
107
107
|
choices.value[index].allowPut = true;
|
|
@@ -2,96 +2,96 @@
|
|
|
2
2
|
import { onMounted, ref, computed, nextTick } from 'vue';
|
|
3
3
|
import { useRenderText } from '../../composables/useRenderText';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
5
|
interface Props {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
multiple?: boolean
|
|
6
|
+
svg: string,
|
|
7
|
+
animation?: "" | "translateX" | "scale",
|
|
8
|
+
multiple?: boolean
|
|
12
9
|
}
|
|
13
10
|
|
|
14
|
-
|
|
15
11
|
const props = withDefaults(defineProps<Props>(), {
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
animation: "",
|
|
13
|
+
multiple: false
|
|
18
14
|
});
|
|
19
15
|
|
|
20
16
|
const svg = ref<string>("");
|
|
21
17
|
|
|
18
|
+
// Refs
|
|
19
|
+
const svgContainer = ref<HTMLElement | null>(null);
|
|
20
|
+
|
|
22
21
|
const animationType = computed(() => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
switch (props.animation) {
|
|
23
|
+
case "translateX":
|
|
24
|
+
return "animate-slide";
|
|
25
|
+
case "scale":
|
|
26
|
+
return "animate-zoom";
|
|
27
|
+
default:
|
|
28
|
+
return "animate-fade";
|
|
29
|
+
}
|
|
31
30
|
});
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
32
|
+
const showScene = (scene: string) => {
|
|
33
|
+
if (!svgContainer.value) return;
|
|
34
|
+
const currentScene = svgContainer.value.querySelector(`[data-scene="${scene}"]`)
|
|
35
|
+
if(!currentScene) return;
|
|
36
|
+
if(!props.multiple){
|
|
37
|
+
hideScenes()
|
|
38
|
+
}
|
|
39
|
+
currentScene.classList.remove('hidden', animationType.value)
|
|
40
|
+
currentScene.classList.add(animationType.value)
|
|
41
|
+
// const scenes = svgContainer.value.getElementsByClassName('scene');
|
|
42
|
+
// Array.from(scenes).forEach((s) => {
|
|
43
|
+
// if (s.classList.contains(`scene-${scene}`)) {
|
|
44
|
+
// s.classList.remove('hidden', animationType.value);
|
|
45
|
+
// s.classList.add(animationType.value);
|
|
46
|
+
// } else {
|
|
47
|
+
// if (!props.multiple && !s.classList.contains('hidden')) {
|
|
48
|
+
// s.classList.add('hidden');
|
|
49
|
+
// s.classList.remove(animationType.value);
|
|
50
|
+
// }
|
|
51
|
+
// }
|
|
52
|
+
// });
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const hideScenes = () => {
|
|
56
|
+
if (!svgContainer.value) return;
|
|
57
|
+
const scenes = svgContainer.value.querySelectorAll('[data-scene]');
|
|
58
|
+
Array.from(scenes).forEach((s) => {
|
|
59
|
+
if (!s.classList.contains('hidden')) {
|
|
60
|
+
s.classList.add('hidden');
|
|
61
|
+
s.classList.remove(animationType.value);
|
|
51
62
|
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
52
65
|
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
onMounted(async () => {
|
|
67
|
+
svg.value = useRenderText(props.svg);
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
Array.from(btns).forEach((b) => {
|
|
58
|
-
b.addEventListener('click', (e) => {
|
|
59
|
-
const scene = b.getAttribute("id");
|
|
60
|
-
showScene(scene?? "");
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
});
|
|
69
|
+
await nextTick();
|
|
65
70
|
|
|
71
|
+
if (!svgContainer.value) return;
|
|
66
72
|
|
|
73
|
+
// Hide all scenes initially
|
|
74
|
+
hideScenes()
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if(!props.multiple && !s.classList.contains('hidden')) {
|
|
79
|
-
s.classList.add('hidden');
|
|
80
|
-
s.classList.remove(animationType.value);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
76
|
+
// Bind click events to buttons
|
|
77
|
+
const btns = svgContainer.value.querySelectorAll('[data-btn]');
|
|
78
|
+
Array.from(btns).forEach((b) => {
|
|
79
|
+
b.classList.add('cursor-pointer')
|
|
80
|
+
b.addEventListener('click', () => {
|
|
81
|
+
const sceneName = b.getAttribute("data-btn")
|
|
82
|
+
showScene(sceneName ?? "");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
87
86
|
|
|
88
87
|
|
|
89
88
|
|
|
90
89
|
</script>
|
|
91
90
|
|
|
92
91
|
|
|
92
|
+
|
|
93
93
|
<template>
|
|
94
94
|
<!-- The buttons must have class "btn" and an unique id="<scene-name>"
|
|
95
95
|
The scenes elements must have class "scene" and "scene-<scene-name>" -->
|
|
96
|
-
<div
|
|
96
|
+
<div ref="svgContainer" v-html="svg"></div>
|
|
97
97
|
</template>
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, onMounted, computed, defineAsyncComponent } from 'vue'
|
|
3
|
+
import { hierarchy, tree, cluster, type HierarchyPointLink, type HierarchyPointNode } from 'd3-hierarchy'
|
|
4
|
+
import * as d3 from 'd3-selection'
|
|
5
|
+
import { linkVertical, linkHorizontal } from 'd3-shape'
|
|
6
|
+
//import { ascending } from 'd3-array'
|
|
7
|
+
import * as d3Zoom from 'd3-zoom'
|
|
8
|
+
import type { TreeNode, ColorPath, ColorRect } from '../../types/Hierarchy'
|
|
9
|
+
import type { NestedComponents } from '../../types/Component'
|
|
10
|
+
import { useComponent } from '../../composables/useComponent'
|
|
11
|
+
import EpModal from '../interactions/EpModal.vue'
|
|
12
|
+
import EpBtn from '../basics/EpBtn.vue'
|
|
13
|
+
import { useRenderText } from '../../composables/useRenderText'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
nodes: TreeNode;
|
|
19
|
+
maxWidth?: number;
|
|
20
|
+
maxHeight?: number;
|
|
21
|
+
labelClose?: string;
|
|
22
|
+
isCluster?:boolean;
|
|
23
|
+
colorPath?:ColorPath;
|
|
24
|
+
colorRect?:ColorRect;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
28
|
+
labelClose: "fermer",
|
|
29
|
+
maxWidth: 800,
|
|
30
|
+
maxHeight: 600,
|
|
31
|
+
isCluster:false,
|
|
32
|
+
colorRect:'fill-main-color-400',
|
|
33
|
+
colorPath:'stroke-yellow-400'
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const treeContainer = ref<HTMLDivElement | null>(null)
|
|
37
|
+
const treeWrapper = ref<HTMLDivElement | null>(null)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
/* control modal */
|
|
41
|
+
type ShowNode = {
|
|
42
|
+
title: string;
|
|
43
|
+
text?: string;
|
|
44
|
+
component?: NestedComponents
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const currentNode = ref<ShowNode | null>(null)
|
|
48
|
+
const showModal = ref(false)
|
|
49
|
+
|
|
50
|
+
const handleNodeClick = (node: TreeNode) => {
|
|
51
|
+
currentNode.value = {
|
|
52
|
+
title: node.name,
|
|
53
|
+
text: node.text,
|
|
54
|
+
component: node.component
|
|
55
|
+
}
|
|
56
|
+
showModal.value = true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const closeModal = () => {
|
|
60
|
+
showModal.value = false
|
|
61
|
+
currentNode.value = null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const currentRenderComponent = computed(() => {
|
|
65
|
+
if (currentNode.value && currentNode.value.component) {
|
|
66
|
+
const componentToLoad = useComponent(currentNode.value.component.type);
|
|
67
|
+
return defineAsyncComponent(() => import(`../${componentToLoad.path}/${componentToLoad.name}.vue`));
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
onMounted(() => {
|
|
73
|
+
if (!treeContainer.value) return
|
|
74
|
+
|
|
75
|
+
if(props.isCluster){
|
|
76
|
+
clusterView()
|
|
77
|
+
}else{
|
|
78
|
+
treeView()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
const treeView = () => {
|
|
87
|
+
const rectW = 130
|
|
88
|
+
const rectH = 40
|
|
89
|
+
const margin = { top: 40, right: 40, bottom: 40, left: 40 }
|
|
90
|
+
|
|
91
|
+
const root = hierarchy<TreeNode>(props.nodes)
|
|
92
|
+
//const totalLeafCount = root.leaves().length
|
|
93
|
+
const width = Math.max(props.maxWidth)
|
|
94
|
+
const height = props.maxHeight
|
|
95
|
+
|
|
96
|
+
const treeLayout = tree<TreeNode>()
|
|
97
|
+
.nodeSize([170, 100]) // [x spacing, y spacing]
|
|
98
|
+
|
|
99
|
+
const treeData = treeLayout(root)
|
|
100
|
+
|
|
101
|
+
const svg = d3.select(treeContainer.value)
|
|
102
|
+
.append('svg')
|
|
103
|
+
.attr('width', width)
|
|
104
|
+
.attr('height', height)
|
|
105
|
+
|
|
106
|
+
const g = svg.append('g')
|
|
107
|
+
.attr('transform', `translate(${margin.left}, ${margin.top})`)
|
|
108
|
+
|
|
109
|
+
const zoom = d3Zoom.zoom<SVGSVGElement, unknown>()
|
|
110
|
+
.scaleExtent([0.5, 2])
|
|
111
|
+
.on('zoom', (event) => {
|
|
112
|
+
g.attr('transform', event.transform)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
svg.call(zoom)
|
|
116
|
+
|
|
117
|
+
const centerX = width / 2 - treeData.x
|
|
118
|
+
const centerY = 30//height / 2 - treeData.y
|
|
119
|
+
const identity = (d3Zoom as any).zoomIdentity
|
|
120
|
+
svg.call(zoom.transform, identity.translate(centerX, centerY))
|
|
121
|
+
|
|
122
|
+
// Links
|
|
123
|
+
const linkPath = linkVertical<HierarchyPointLink<TreeNode>, HierarchyPointNode<TreeNode>>()
|
|
124
|
+
.x(d => d.x)
|
|
125
|
+
.y(d => d.y)
|
|
126
|
+
|
|
127
|
+
g.selectAll('path.link')
|
|
128
|
+
.data(treeData.links())
|
|
129
|
+
.enter()
|
|
130
|
+
.append('path')
|
|
131
|
+
.attr('d', d => linkPath(d))
|
|
132
|
+
.attr('class', d => {
|
|
133
|
+
const link = d.target.data.active ? `${props.colorPath} stroke-2` : 'stroke-black dark:stroke-white'
|
|
134
|
+
return `${link} link fill-none`
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
// Nodes
|
|
138
|
+
const node = g.selectAll('g.node')
|
|
139
|
+
.data(treeData.descendants())
|
|
140
|
+
.enter()
|
|
141
|
+
.append('g')
|
|
142
|
+
.attr('class', 'node')
|
|
143
|
+
.attr('transform', d => `translate(${d.x}, ${d.y})`)
|
|
144
|
+
.style('cursor', d => (d.data.component || d.data.text ? 'pointer' : 'default'))
|
|
145
|
+
.each(function (d) {
|
|
146
|
+
if (d.data.component || d.data.text) {
|
|
147
|
+
d3.select(this).on('click', (_event) => handleNodeClick(d.data))
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
//.style('cursor', 'pointer')
|
|
151
|
+
//.on('click', (_event, d) => handleNodeClick(d.data))
|
|
152
|
+
|
|
153
|
+
node.each(function (d) {
|
|
154
|
+
const group = d3.select(this)
|
|
155
|
+
|
|
156
|
+
// Append text temporarily
|
|
157
|
+
const text = group.append('text')
|
|
158
|
+
.attr('class', 'text-sm font-semibold fill-black dark:fill-white')
|
|
159
|
+
.attr('text-anchor', 'middle')
|
|
160
|
+
.attr('x', 0)
|
|
161
|
+
.attr('y', 0)
|
|
162
|
+
.attr('dy', '.35em')
|
|
163
|
+
.text(d.data.name)
|
|
164
|
+
|
|
165
|
+
// Get bounding box to determine text size
|
|
166
|
+
const bbox = (text.node() as SVGTextElement).getBBox()
|
|
167
|
+
const paddingX = 10
|
|
168
|
+
const paddingY = 10
|
|
169
|
+
|
|
170
|
+
const width = bbox.width + paddingX * 2
|
|
171
|
+
const height = bbox.height + paddingY * 2
|
|
172
|
+
|
|
173
|
+
// Draw rect using text size
|
|
174
|
+
group.insert('rect', 'text')
|
|
175
|
+
.attr('class', props.colorRect)
|
|
176
|
+
.attr('x', -width / 2)
|
|
177
|
+
.attr('y', -height / 2)
|
|
178
|
+
.attr('width', width)
|
|
179
|
+
.attr('height', height)
|
|
180
|
+
.attr('rx', 4)
|
|
181
|
+
.attr('ry', 4)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
node.append('text')
|
|
186
|
+
.attr('x', 0)
|
|
187
|
+
.attr('y', 0)
|
|
188
|
+
.attr('dy', '.35em')
|
|
189
|
+
.attr('class', 'text-sm font-semibold fill-white dark:fill-black')
|
|
190
|
+
.attr('text-anchor', 'middle')
|
|
191
|
+
.text(d => d.data.name)
|
|
192
|
+
.style('pointer-events', 'none')
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const clusterView = () => {
|
|
196
|
+
const rectW = 130
|
|
197
|
+
const rectH = 40
|
|
198
|
+
const margin = { top: 40, right: 40, bottom: 40, left: 40 }
|
|
199
|
+
|
|
200
|
+
const root = hierarchy<TreeNode>(props.nodes)
|
|
201
|
+
//const totalLeafCount = root.leaves().length
|
|
202
|
+
const width = Math.max(props.maxWidth)
|
|
203
|
+
const height = props.maxHeight
|
|
204
|
+
|
|
205
|
+
const treeLayout = cluster<TreeNode>()
|
|
206
|
+
.nodeSize([130, 130]) // [x spacing, y spacing]
|
|
207
|
+
|
|
208
|
+
const treeData = treeLayout(root)
|
|
209
|
+
|
|
210
|
+
const svg = d3.select(treeContainer.value)
|
|
211
|
+
.append('svg')
|
|
212
|
+
.attr('width', width)
|
|
213
|
+
.attr('height', height)
|
|
214
|
+
|
|
215
|
+
const g = svg.append('g')
|
|
216
|
+
.attr('transform', `translate(${margin.left}, ${margin.top})`)
|
|
217
|
+
|
|
218
|
+
const zoom = d3Zoom.zoom<SVGSVGElement, unknown>()
|
|
219
|
+
.scaleExtent([0.1, 4])
|
|
220
|
+
.on('zoom', (event) => {
|
|
221
|
+
g.attr('transform', event.transform)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
svg.call(zoom)
|
|
225
|
+
|
|
226
|
+
const centerX = 30
|
|
227
|
+
const centerY = height / 2 - treeData.x
|
|
228
|
+
const identity = (d3Zoom as any).zoomIdentity
|
|
229
|
+
svg.call(zoom.transform, identity.translate(centerX, centerY))
|
|
230
|
+
|
|
231
|
+
// Links
|
|
232
|
+
const linkPath = linkHorizontal<HierarchyPointLink<TreeNode>, HierarchyPointNode<TreeNode>>()
|
|
233
|
+
.x(d => d.y)
|
|
234
|
+
.y(d => d.x)
|
|
235
|
+
|
|
236
|
+
g.selectAll('path.link')
|
|
237
|
+
.data(treeData.links())
|
|
238
|
+
.enter()
|
|
239
|
+
.append('path')
|
|
240
|
+
.attr('d', d => linkPath(d))
|
|
241
|
+
.attr('class', d => {
|
|
242
|
+
const link = d.target.data.active ? `${props.colorPath} stroke-2` : 'stroke-black dark:stroke-white'
|
|
243
|
+
return `${link} link fill-none`
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
// Nodes
|
|
247
|
+
const node = g.selectAll('g.node')
|
|
248
|
+
.data(treeData.descendants())
|
|
249
|
+
.enter()
|
|
250
|
+
.append('g')
|
|
251
|
+
.attr('class', 'node')
|
|
252
|
+
.attr('transform', d => `translate(${d.y}, ${d.x})`)
|
|
253
|
+
.style('cursor', d => (d.data.component || d.data.text ? 'pointer' : 'default'))
|
|
254
|
+
.each(function (d) {
|
|
255
|
+
if (d.data.component || d.data.text) {
|
|
256
|
+
d3.select(this).on('click', (_event) => handleNodeClick(d.data))
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
//.style('cursor', 'pointer')
|
|
260
|
+
//.on('click', (_event, d) => handleNodeClick(d.data))
|
|
261
|
+
|
|
262
|
+
node.each(function (d) {
|
|
263
|
+
const group = d3.select(this)
|
|
264
|
+
|
|
265
|
+
// Append text temporarily
|
|
266
|
+
const text = group.append('text')
|
|
267
|
+
.attr('class', 'text-sm font-semibold fill-black dark:fill-white')
|
|
268
|
+
.attr('text-anchor', 'middle')
|
|
269
|
+
.attr('x', 0)
|
|
270
|
+
.attr('y', 0)
|
|
271
|
+
.attr('dy', '.35em')
|
|
272
|
+
.text(d.data.name)
|
|
273
|
+
|
|
274
|
+
// Get bounding box to determine text size
|
|
275
|
+
const bbox = (text.node() as SVGTextElement).getBBox()
|
|
276
|
+
const paddingX = 10
|
|
277
|
+
const paddingY = 10
|
|
278
|
+
|
|
279
|
+
const width = bbox.width + paddingX * 2
|
|
280
|
+
const height = bbox.height + paddingY * 2
|
|
281
|
+
|
|
282
|
+
// Draw rect using text size
|
|
283
|
+
group.insert('rect', 'text')
|
|
284
|
+
.attr('class', props.colorRect)
|
|
285
|
+
.attr('x', -width / 2)
|
|
286
|
+
.attr('y', -height / 2)
|
|
287
|
+
.attr('width', width)
|
|
288
|
+
.attr('height', height)
|
|
289
|
+
.attr('rx', 4)
|
|
290
|
+
.attr('ry', 4)
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
node.append('text')
|
|
295
|
+
.attr('x', 0)
|
|
296
|
+
.attr('y', 0)
|
|
297
|
+
.attr('dy', '.35em')
|
|
298
|
+
.attr('class', 'text-sm font-semibold fill-white dark:fill-black')
|
|
299
|
+
.attr('text-anchor', 'middle')
|
|
300
|
+
.text(d => d.data.name)
|
|
301
|
+
.style('pointer-events', 'none')
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
const maxW = computed(() => {
|
|
308
|
+
return `${props.maxWidth.toString()}px`
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
const maxH = computed(() => {
|
|
312
|
+
return `${props.maxWidth.toString()}px`
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
</script>
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
<template>
|
|
319
|
+
<div>
|
|
320
|
+
<div ref="treeWrapper" class="tree-wrapper mx-auto" :style="{ maxHeight: maxH, maxWidth: maxW }">
|
|
321
|
+
<div ref="treeContainer" class="tree-container"></div>
|
|
322
|
+
</div>
|
|
323
|
+
<EpModal v-model="showModal" :title="currentNode.title" v-if="currentNode">
|
|
324
|
+
<div v-if="currentNode.text" v-html="useRenderText(currentNode.text)"></div>
|
|
325
|
+
<template v-if="currentRenderComponent && currentNode.component">
|
|
326
|
+
<component :is="currentRenderComponent" v-bind="{ ...currentNode.component.data }" />
|
|
327
|
+
</template>
|
|
328
|
+
<div class="flex justify-end">
|
|
329
|
+
<EpBtn @click="closeModal" type="error" outlined rounded>{{ labelClose }}</EpBtn>
|
|
330
|
+
</div>
|
|
331
|
+
</EpModal>
|
|
332
|
+
</div>
|
|
333
|
+
</template>
|
|
334
|
+
|
|
335
|
+
<style scoped>
|
|
336
|
+
.tree-wrapper {
|
|
337
|
+
overflow: auto;
|
|
338
|
+
border: 1px solid #ddd;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.tree-container {
|
|
342
|
+
width: 100%;
|
|
343
|
+
overflow-x: auto;
|
|
344
|
+
}
|
|
345
|
+
</style>
|
|
@@ -17,7 +17,6 @@ interface Props {
|
|
|
17
17
|
title: string;
|
|
18
18
|
mandateLevel?:MandateLevel | null;
|
|
19
19
|
intentions?: string;
|
|
20
|
-
version_link?: null;
|
|
21
20
|
hideCover?: boolean;
|
|
22
21
|
version?: string;
|
|
23
22
|
type?:MediaVariants;
|
|
@@ -65,7 +64,7 @@ const { title, intentions, cover, hideCover, version, labelCard, hideIcon, manda
|
|
|
65
64
|
<template v-if="!hideCover">
|
|
66
65
|
<img
|
|
67
66
|
v-if="hasCover"
|
|
68
|
-
class="
|
|
67
|
+
class="h-24 w-full rounded-t-lg object-cover md:h-auto md:w-24 md:rounded-none md:rounded-l-lg"
|
|
69
68
|
:src="cover"
|
|
70
69
|
:alt="`image de la lecture ${title}`"
|
|
71
70
|
/>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {ref} from 'vue'
|
|
3
|
+
import EpModal from '../interactions/EpModal.vue';
|
|
4
|
+
import type { NestedComponents } from '../../types/Component';
|
|
5
|
+
import EpBtn from '../basics/EpBtn.vue';
|
|
6
|
+
import EpDivider from '../basics/EpDivider.vue';
|
|
7
|
+
import TextMedia from './TextMedia.vue';
|
|
8
|
+
const showModal = ref(false)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
title?:string;
|
|
13
|
+
content:string;
|
|
14
|
+
labelClose?:string;
|
|
15
|
+
media?:NestedComponents
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
19
|
+
title:"Voir détails",
|
|
20
|
+
labelClose:"Fermer"
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<div class="cursor-pointer rounded bg-primary text-white py-2 px-4 flex flex-col items-center" @click="showModal = true">
|
|
27
|
+
<EpModal v-model="showModal" :title="content">
|
|
28
|
+
<TextMedia
|
|
29
|
+
:text="title"
|
|
30
|
+
:media="media"
|
|
31
|
+
/>
|
|
32
|
+
<EpDivider/>
|
|
33
|
+
<div class="flex justify-end">
|
|
34
|
+
<EpBtn
|
|
35
|
+
type="error"
|
|
36
|
+
rounded
|
|
37
|
+
size="small"
|
|
38
|
+
@click="showModal = false">
|
|
39
|
+
{{labelClose}}
|
|
40
|
+
</EpBtn>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
</EpModal>
|
|
44
|
+
<p class="dark:text-black">{{title}}</p>
|
|
45
|
+
</div>
|
|
46
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {computed, defineAsyncComponent} from "vue"
|
|
3
|
+
import { useRenderText } from '../../composables/useRenderText';
|
|
4
|
+
import { useComponent } from "../../composables/useComponent";
|
|
5
|
+
import type { NestedComponents } from "../../types/Component";
|
|
6
|
+
|
|
7
|
+
interface Props{
|
|
8
|
+
media?:NestedComponents;
|
|
9
|
+
text:string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const currentRenderComponent = computed(() => {
|
|
16
|
+
if (props.media) {
|
|
17
|
+
const componentToLoad = useComponent(props.media.type);
|
|
18
|
+
return defineAsyncComponent(() => import(`../${componentToLoad.path}/${componentToLoad.name}.vue`));
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<div class="flex items-center justify-center gap-1">
|
|
27
|
+
<div class="w-full" v-html="useRenderText(text)"></div>
|
|
28
|
+
<div class="w-full" v-if="currentRenderComponent && media">
|
|
29
|
+
<component
|
|
30
|
+
:is="currentRenderComponent"
|
|
31
|
+
v-bind="{...media.data}"/>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
package/dist/BgAudio-ryf2FIxF.js
DELETED
package/dist/EpAlert-BUiXiWRL.js
DELETED
package/dist/EpAudio-CkZrkt3Z.js
DELETED
package/dist/EpBadge-vOdZrc0e.js
DELETED