ep-lib-ts 1.0.47 → 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-DKSyFe8_.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-B6I1LZM8.js → EpDraggable-BwpIpRyf.js} +46 -46
- 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-BLfdye3a.js → EpInput-uDeg10dD.js} +29 -29
- 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-snrOZLuu.js → EpList-BI7oPTHl.js} +1 -1
- package/dist/EpModal-DN-QQzrQ.js +4 -0
- package/dist/{EpNothing-ChU4qO5j.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 -6
- package/dist/components/educationals/EpDocument.vue.d.ts +44 -0
- 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 +3 -1
- package/dist/components/tools/{TextImg.vue.d.ts → TextMedia.vue.d.ts} +3 -2
- package/dist/ep-lib-ts.js +41 -39
- package/dist/ep-lib-ts.umd.cjs +212 -212
- package/dist/{index-QY-UvpNr.js → index-DH1gIdAA.js} +1 -1
- package/dist/{index-D6RVSyf7.js → index-DeiLPw0s.js} +10899 -8250
- package/dist/index.d.ts +3 -1
- package/dist/{prism-Cv4D8Rjm.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 -172
- package/src/components/educationals/EpDocument.vue +92 -0
- package/src/components/interactions/EpContentSlider.vue +1 -1
- package/src/components/medias/EpHierarchy.vue +345 -0
- package/src/components/medias/EpSoftware.vue +1 -2
- package/src/components/tools/Details.vue +8 -10
- package/src/components/tools/TextMedia.vue +34 -0
- package/dist/BgAudio-CFZeS_dQ.js +0 -4
- package/dist/Details-D_yxeUuE.js +0 -4
- package/dist/DisplayBox-D8hlc9Gn.js +0 -4
- package/dist/EpAlert-RMp39gBY.js +0 -4
- package/dist/EpAudio-VXqSaCc0.js +0 -4
- package/dist/EpAvatar-CoBsHAyN.js +0 -4
- package/dist/EpBadge-Di0ORWOa.js +0 -4
- package/dist/EpBarChart-D0FaZPGz.js +0 -4
- package/dist/EpBtn-D5wu8yT7.js +0 -4
- package/dist/EpCard-Drdckmbx.js +0 -4
- package/dist/EpCardLink-DUGjSAGF.js +0 -4
- package/dist/EpChip-DDochFMT.js +0 -4
- package/dist/EpCodeblock-BjxiWHoc.js +0 -4
- package/dist/EpConclusion-CXoGHiG1.js +0 -4
- package/dist/EpContentSlider-HBkmUIw5.js +0 -4
- package/dist/EpDescription-BmRR6d2p.js +0 -4
- package/dist/EpDivider-BALEThPk.js +0 -4
- package/dist/EpEdu-D7erj5ED.js +0 -4
- package/dist/EpFlex-CdriG_tC.js +0 -4
- package/dist/EpFunnelChart-HVjlJWQd.js +0 -4
- package/dist/EpHeader-Bl4162yt.js +0 -4
- package/dist/EpHover-CVY1squO.js +0 -4
- package/dist/EpHoverCard-BIuPau4X.js +0 -4
- package/dist/EpIcon-DsCeMM28.js +0 -4
- package/dist/EpIframe-Cz5g1BYb.js +0 -4
- package/dist/EpImg-Ccr76yR5.js +0 -4
- package/dist/EpImgCarousel-Ddz1Ur0L.js +0 -4
- package/dist/EpInstructions-B-b52LnB.js +0 -4
- package/dist/EpIntroduction-DEaiE8_Q.js +0 -4
- package/dist/EpLineChart-CJ28vhHx.js +0 -4
- package/dist/EpLink-DRGrCSOs.js +0 -4
- package/dist/EpLinkVersion-DJcPV4xm.js +0 -4
- package/dist/EpModal-m4szNip0.js +0 -4
- package/dist/EpObjective-CAXtephy.js +0 -4
- package/dist/EpPieChart-B3l-Y3E9.js +0 -4
- package/dist/EpQuestion-CrXTzzzu.js +0 -4
- package/dist/EpQuote-Dc-IZjOX.js +0 -4
- package/dist/EpRadio-CA0CASuz.js +0 -4
- package/dist/EpRadioSummative-Bm2JDs6z.js +0 -4
- package/dist/EpReading-BNArWsC2.js +0 -4
- package/dist/EpResource-Bx1G7Dlz.js +0 -4
- package/dist/EpScope-CB6RuO3X.js +0 -4
- package/dist/EpSection-BUBgMeo9.js +0 -4
- package/dist/EpSectionCols-rigTAR3l.js +0 -4
- package/dist/EpSkeleton-B9HFmS5A.js +0 -4
- package/dist/EpSoftware-CK9VPoFF.js +0 -4
- package/dist/EpSpecificObjective-Dm-H_StM.js +0 -4
- package/dist/EpSpinner-Br8tW9f2.js +0 -4
- package/dist/EpStackedList-By0U0h1R.js +0 -4
- package/dist/EpSummativeTable-Czo4hRQq.js +0 -4
- package/dist/EpSvg-BVV9GJ09.js +0 -4
- package/dist/EpSvgShow-DSPDvQlK.js +0 -4
- package/dist/EpTable-CNPciiRt.js +0 -4
- package/dist/EpTerm-BjD-0L65.js +0 -4
- package/dist/EpText-8IGa40sW.js +0 -4
- package/dist/EpTimeLine-D5R81tuv.js +0 -4
- package/dist/EpVideo-v6GnvLIU.js +0 -4
- package/dist/EpVideoPanopto-BWVr3ji1.js +0 -4
- package/dist/EpWordDef-QB2ioxjp.js +0 -4
- package/dist/TextImg-B_cSkkBi.js +0 -4
- package/src/components/tools/TextImg.vue +0 -28
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { toRefs, computed } from "vue";
|
|
3
|
+
import EpCard from "../basics/EpCard.vue";
|
|
4
|
+
import EpIcon from '../basics/EpIcon.vue'
|
|
5
|
+
import { mdiFile } from '@mdi/js';
|
|
6
|
+
import { mdiArrowCollapseDown } from '@mdi/js';
|
|
7
|
+
import { mdiOpenInNew } from '@mdi/js';
|
|
8
|
+
import EpBtn from "../basics/EpBtn.vue";
|
|
9
|
+
import { useRenderText } from "../../composables/useRenderText";
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
url:string;
|
|
13
|
+
src?: string | null;
|
|
14
|
+
icon?:string;
|
|
15
|
+
title?:string;
|
|
16
|
+
description?:string;
|
|
17
|
+
hideIcon?:boolean;
|
|
18
|
+
labelOpen?:string;
|
|
19
|
+
labelDownload?:string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
23
|
+
src: null,
|
|
24
|
+
hideIcon:false,
|
|
25
|
+
labelDownload:"Télécharger",
|
|
26
|
+
labelOpen:"Ouvrir"
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const fileDownloadExtensions = [
|
|
32
|
+
'doc', 'docx',
|
|
33
|
+
'xls', 'xlsx',
|
|
34
|
+
'ppt', 'pptx',
|
|
35
|
+
'rtf',
|
|
36
|
+
'odt', 'ods', 'odp'
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const getExtension = (url: string): string => {
|
|
40
|
+
const queryRemoved = url.split('?')[0];
|
|
41
|
+
const parts = queryRemoved.split('.');
|
|
42
|
+
return parts.length > 1 ? parts.pop()!.toLowerCase() : '';
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
const shouldDownload = computed(() => {
|
|
47
|
+
const ext = getExtension(props.url);
|
|
48
|
+
return fileDownloadExtensions.includes(ext);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const iconBtn = computed(() => {
|
|
52
|
+
return shouldDownload.value ? mdiArrowCollapseDown : mdiOpenInNew;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const label = computed(() => {
|
|
56
|
+
return shouldDownload.value ? props.labelDownload : props.labelOpen;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const renderIcon = computed(()=> {
|
|
60
|
+
return props.icon ? props.icon : mdiFile
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
const { src, hideIcon } = toRefs(props);
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<template>
|
|
70
|
+
<div class="w-3/6 mx-auto">
|
|
71
|
+
<EpCard>
|
|
72
|
+
<div :class="`md:flex md:flex-wrap rounded-md`">
|
|
73
|
+
<div class="w-1/5 mr-6" v-if="src">
|
|
74
|
+
<img :class="`md:w-full md:h-full md:object-cover rounded-md`" :src="src"
|
|
75
|
+
alt="Image of quote" />
|
|
76
|
+
</div>
|
|
77
|
+
<div class="flex items-center justify-center px-7" v-else-if="!hideIcon">
|
|
78
|
+
<div class="text-base dark:text-white'">
|
|
79
|
+
<EpIcon :size="60" :icon-path="renderIcon"></EpIcon>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
<div :class="`py-6 flex-1 ${hideIcon?'px-6':'pr-2'}`">
|
|
83
|
+
<h4 class="text-2xl font-semibold mb-4" v-if="title">{{ title }}</h4>
|
|
84
|
+
<div class="mb-3" v-if="description" v-html="useRenderText(description)"></div>
|
|
85
|
+
<EpBtn :href="url" block type="primary" rounded :prepend-icon="iconBtn">
|
|
86
|
+
{{label}}
|
|
87
|
+
</EpBtn>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</EpCard>
|
|
91
|
+
</div>
|
|
92
|
+
</template>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, computed, defineAsyncComponent,
|
|
2
|
+
import { ref, computed, defineAsyncComponent, ComponentPublicInstance } from "vue";
|
|
3
3
|
import { type SlidesType } from "../../types/Slides";
|
|
4
4
|
import { useComponent } from "../../composables/useComponent";
|
|
5
5
|
import { useRenderText } from "../../composables/useRenderText";
|
|
@@ -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
|
/>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import {ref} from 'vue'
|
|
3
3
|
import EpModal from '../interactions/EpModal.vue';
|
|
4
|
-
import {
|
|
4
|
+
import type { NestedComponents } from '../../types/Component';
|
|
5
5
|
import EpBtn from '../basics/EpBtn.vue';
|
|
6
6
|
import EpDivider from '../basics/EpDivider.vue';
|
|
7
|
-
import
|
|
7
|
+
import TextMedia from './TextMedia.vue';
|
|
8
8
|
const showModal = ref(false)
|
|
9
9
|
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ interface Props {
|
|
|
12
12
|
title?:string;
|
|
13
13
|
content:string;
|
|
14
14
|
labelClose?:string;
|
|
15
|
-
|
|
15
|
+
media?:NestedComponents
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -24,14 +24,12 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
24
24
|
|
|
25
25
|
<template>
|
|
26
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">
|
|
28
|
-
<
|
|
29
|
-
:text="
|
|
30
|
-
:
|
|
31
|
-
:alt="`image ${title}`"
|
|
27
|
+
<EpModal v-model="showModal" :title="content">
|
|
28
|
+
<TextMedia
|
|
29
|
+
:text="title"
|
|
30
|
+
:media="media"
|
|
32
31
|
/>
|
|
33
32
|
<EpDivider/>
|
|
34
|
-
<p>{{title}}</p>
|
|
35
33
|
<div class="flex justify-end">
|
|
36
34
|
<EpBtn
|
|
37
35
|
type="error"
|
|
@@ -43,6 +41,6 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
43
41
|
</div>
|
|
44
42
|
|
|
45
43
|
</EpModal>
|
|
46
|
-
<p>{{title}}</p>
|
|
44
|
+
<p class="dark:text-black">{{title}}</p>
|
|
47
45
|
</div>
|
|
48
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-CFZeS_dQ.js
DELETED
package/dist/Details-D_yxeUuE.js
DELETED
package/dist/EpAlert-RMp39gBY.js
DELETED
package/dist/EpAudio-VXqSaCc0.js
DELETED
package/dist/EpBadge-Di0ORWOa.js
DELETED
package/dist/EpBtn-D5wu8yT7.js
DELETED
package/dist/EpCard-Drdckmbx.js
DELETED
package/dist/EpChip-DDochFMT.js
DELETED
package/dist/EpEdu-D7erj5ED.js
DELETED
package/dist/EpFlex-CdriG_tC.js
DELETED
package/dist/EpHover-CVY1squO.js
DELETED