@tekkare/romulus 0.1.138 → 0.1.140

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/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.16.0"
6
6
  },
7
- "version": "0.1.137",
7
+ "version": "0.1.139",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
@@ -0,0 +1,93 @@
1
+ <!--
2
+ RmClampText - un texte long coupe a N lignes, avec « Lire plus ».
3
+
4
+ Les fiches produit portent des paragraphes de longueur imprevisible : une
5
+ indication tient parfois en deux lignes, parfois en quarante. Les laisser
6
+ couler pousse tout le reste de la carte hors de l'ecran ; les couper sans
7
+ rien dire fait perdre le texte.
8
+
9
+ Le lien n'apparait que si le texte deborde vraiment. La mesure se fait dans
10
+ l'etat coupe (`scrollHeight > clientHeight`) et se refait au
11
+ redimensionnement : une carte elargie peut faire tenir le texte, le lien
12
+ doit alors disparaitre. Une fois deplie, on ne remesure pas — l'element
13
+ n'est plus coupe, la comparaison rendrait toujours faux et le lien
14
+ « Reduire » s'effacerait sous le doigt.
15
+ -->
16
+ <script setup lang="ts">
17
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
18
+
19
+ const props = withDefaults(defineProps<{
20
+ /** Le texte a afficher. Vide, le composant ne rend rien. */
21
+ text?: string | null
22
+ /** Nombre de lignes visibles avant la coupe. */
23
+ lines?: number
24
+ lang?: 'fr' | 'en'
25
+ }>(), {
26
+ text: '',
27
+ lines: 6,
28
+ lang: 'fr',
29
+ })
30
+
31
+ const WORDS = {
32
+ fr: { more: 'Lire plus', less: 'Réduire' },
33
+ en: { more: 'Read more', less: 'Show less' },
34
+ } as const
35
+
36
+ const words = computed(() => WORDS[props.lang])
37
+
38
+ const bodyRef = ref<HTMLElement>()
39
+ const expanded = ref(false)
40
+ const overflows = ref(false)
41
+
42
+ async function measure() {
43
+ if (expanded.value) return
44
+ await nextTick()
45
+ const el = bodyRef.value
46
+ if (!el) return
47
+ overflows.value = el.scrollHeight > el.clientHeight
48
+ }
49
+
50
+ let observer: ResizeObserver | undefined
51
+
52
+ onMounted(() => {
53
+ measure()
54
+ if (typeof ResizeObserver !== 'undefined' && bodyRef.value) {
55
+ observer = new ResizeObserver(() => measure())
56
+ observer.observe(bodyRef.value)
57
+ }
58
+ })
59
+ onBeforeUnmount(() => observer?.disconnect())
60
+
61
+ // Un changement de texte remet la coupe : le paragraphe suivant n'a aucune
62
+ // raison d'heriter du « deplie » demande sur le precedent.
63
+ watch(() => props.text, () => {
64
+ expanded.value = false
65
+ measure()
66
+ })
67
+ </script>
68
+
69
+ <template>
70
+ <div v-if="text" class="rm-clamp">
71
+ <p
72
+ ref="bodyRef"
73
+ class="rm-clamp__body"
74
+ :class="{ 'rm-clamp__body--cut': !expanded }"
75
+ :style="{ '--rm-clamp-lines': lines }"
76
+ >
77
+ {{ text }}
78
+ </p>
79
+ <button
80
+ v-if="overflows"
81
+ type="button"
82
+ class="rm-clamp__toggle"
83
+ :aria-expanded="expanded"
84
+ @click="expanded = !expanded"
85
+ >
86
+ {{ expanded ? words.less : words.more }}
87
+ </button>
88
+ </div>
89
+ </template>
90
+
91
+ <style scoped>
92
+ .rm-clamp{max-width:100%;min-width:0;overflow:hidden}.rm-clamp__body{color:var(--text-secondary);font-size:var(--font-14);line-height:1.6;overflow-wrap:break-word;word-break:break-word}.rm-clamp__body--cut{display:-webkit-box;-webkit-line-clamp:var(--rm-clamp-lines);line-clamp:var(--rm-clamp-lines);-webkit-box-orient:vertical;overflow:hidden}.rm-clamp__toggle{background:none;border:none;color:var(--color-healthcare);cursor:pointer;display:inline-block;font-family:inherit;font-size:var(--font-13);font-weight:var(--weight-semibold);margin-top:var(--space-4);padding:0}.rm-clamp__toggle:hover{text-decoration:underline}
93
+ </style>
@@ -67,5 +67,5 @@ withDefaults(defineProps<{
67
67
  </template>
68
68
 
69
69
  <style scoped>
70
- .rm-product-card{align-self:stretch;background-color:var(--bg-surface);background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:var(--radius-xl,12px);box-shadow:0 6px 8px 0 rgba(var(--shadow-rgb,30 41 59),.1);display:flex;flex-direction:column;position:relative}.rm-product-card--padded{padding:var(--space-40)}.rm-product-card--healthcare{border:1px solid rgba(var(--healthcare-rgb),.1)}.rm-product-card--discovery{border:1px solid rgba(var(--discovery-rgb),.1)}.rm-product-card--databank{border:1px solid rgba(var(--databank-rgb),.1)}.rm-product-card--pharma{border:1px solid rgba(var(--pharma-rgb),.1)}.rm-product-card__inner{align-items:flex-start;align-self:stretch;display:flex;flex-direction:column;gap:var(--space-24)}.rm-product-card__inner--overlay{backdrop-filter:blur(5px);background:rgba(var(--surface-rgb),.7);border-radius:var(--radius-md,8px);gap:var(--space-16);margin:24px;padding:var(--space-24);width:calc(100% - 48px)}.rm-product-card__title{font-size:26px;font-weight:900;line-height:normal}.rm-product-card--healthcare .rm-product-card__title{color:var(--color-primary)}.rm-product-card--discovery .rm-product-card__title{color:var(--color-discovery)}.rm-product-card--databank .rm-product-card__title{color:var(--color-databank)}.rm-product-card--pharma .rm-product-card__title{color:var(--color-pharma)}.rm-product-card__text{color:var(--text-primary);max-width:550px}.rm-product-card__actions{align-items:center;display:flex;gap:var(--space-16)}
70
+ .rm-product-card{align-self:stretch;background-color:var(--bg-surface);background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:var(--radius-xl,12px);box-shadow:0 6px 8px 0 rgba(var(--shadow-rgb,30 41 59),.1);display:flex;flex-direction:column;position:relative}.rm-product-card--padded{padding:var(--space-40)}.rm-product-card--healthcare{border:1px solid rgba(var(--healthcare-rgb),.1)}.rm-product-card--discovery{border:1px solid rgba(var(--discovery-rgb),.1)}.rm-product-card--databank{border:1px solid rgba(var(--databank-rgb),.1)}.rm-product-card--pharma{border:1px solid rgba(var(--pharma-rgb),.1)}.rm-product-card__inner{align-items:flex-start;align-self:stretch;display:flex;flex-direction:column;gap:var(--space-24)}.rm-product-card__inner--overlay{backdrop-filter:blur(5px);background:rgba(var(--surface-rgb),.7);border-radius:var(--radius-md,8px);gap:var(--space-16);margin:24px;padding:var(--space-24)}.rm-product-card__title{font-size:26px;font-weight:900;line-height:normal}.rm-product-card--healthcare .rm-product-card__title{color:var(--color-primary)}.rm-product-card--discovery .rm-product-card__title{color:var(--color-discovery)}.rm-product-card--databank .rm-product-card__title{color:var(--color-databank)}.rm-product-card--pharma .rm-product-card__title{color:var(--color-pharma)}.rm-product-card__text{color:var(--text-primary);max-width:550px}.rm-product-card__actions{align-items:center;display:flex;gap:var(--space-16)}
71
71
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekkare/romulus",
3
- "version": "0.1.138",
3
+ "version": "0.1.140",
4
4
  "description": "Romulus Design System - Nuxt module by Tekkare",
5
5
  "license": "MIT",
6
6
  "type": "module",