Skip to content

Commit 3185999

Browse files
committed
Clamp matchmaking card intro previews by character count.
Use a fixed text preview length with Show more/Show less toggling so long descriptions stay concise while preserving full content on demand. Made-with: Cursor
1 parent 8fbb585 commit 3185999

1 file changed

Lines changed: 15 additions & 46 deletions

File tree

resources/js/components/matchmaking/ToolCard.vue

Lines changed: 15 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div class="flex h-full min-h-[430px] flex-col bg-white rounded-lg overflow-hidden">
2+
<div class="flex h-[430px] flex-col bg-white rounded-lg overflow-hidden">
33
<div
44
class="flex-shrink-0 flex justify-center items-center w-full h-[178px] bg-white"
55
>
@@ -58,21 +58,17 @@
5858

5959
<div
6060
v-if="tool.description"
61-
ref="descriptionContainerRef"
6261
class="flex-grow min-h-0"
63-
:class="{ 'overflow-hidden': needShowMore && !showMore }"
6462
>
6563
<div
66-
ref="descriptionRef"
67-
class="relative flex-grow text-slate-500 text-[16px] leading-[22px] mb-2 overflow-hidden"
68-
style="height: auto"
64+
class="relative flex-grow text-slate-500 text-[16px] leading-[22px] mb-2"
6965
>
70-
<div v-html="formatMultiline(tool.description)" />
66+
<div v-html="formatMultiline(showMore ? tool.description : getCollapsedText(tool.description))" />
7167

7268
<div
73-
v-if="needShowMore"
69+
v-if="isCollapsible(tool.description)"
7470
class="flex justify-end bottom-0 right-0 bg-white pl-0.5 text-dark-blue"
75-
:class="{ absolute: !showMore, 'w-full': showMore }"
71+
:class="{ absolute: !showMore }"
7672
>
7773
<button @click="onToggleShowMore">
7874
{{ showMore ? 'Show less' : '... Show more' }}
@@ -111,9 +107,8 @@ export default {
111107
},
112108
data() {
113109
return {
114-
descriptionHeight: 'auto',
115-
needShowMore: true,
116110
showMore: false,
111+
previewMaxChars: 190,
117112
};
118113
},
119114
methods: {
@@ -130,46 +125,20 @@ export default {
130125
const normalized = String(value).replace(/\r\n?/g, '\n');
131126
return this.escapeHtml(normalized).replace(/\n/g, '<br>');
132127
},
133-
computeDescriptionHeight() {
134-
const containerEl = this.$refs.descriptionContainerRef;
135-
const descriptionEl = this.$refs.descriptionRef;
136-
if (!containerEl || !descriptionEl) {
137-
return;
128+
getCollapsedText(value = '') {
129+
const normalized = String(value).replace(/\s+/g, ' ').trim();
130+
if (normalized.length <= this.previewMaxChars) {
131+
return normalized;
138132
}
139133
140-
const maxHeight = containerEl.clientHeight;
141-
const rows = Math.floor(maxHeight / 22);
142-
descriptionEl.style.height = 'auto';
143-
this.descriptionHeight = 'auto';
144-
145-
this.needShowMore = descriptionEl.offsetHeight > maxHeight;
146-
if (descriptionEl.offsetHeight > maxHeight) {
147-
descriptionEl.style.height = `${rows * 22}px`;
148-
this.descriptionHeight = `${rows * 22}px`;
149-
} else {
150-
this.showMore = false;
151-
}
134+
return `${normalized.slice(0, this.previewMaxChars).trimEnd()}...`;
135+
},
136+
isCollapsible(value = '') {
137+
const normalized = String(value).replace(/\s+/g, ' ').trim();
138+
return normalized.length > this.previewMaxChars;
152139
},
153140
onToggleShowMore() {
154-
const descriptionEl = this.$refs.descriptionRef;
155-
if (!descriptionEl) {
156-
return;
157-
}
158-
159141
this.showMore = !this.showMore;
160-
if (!this.showMore) {
161-
descriptionEl.style.height = this.descriptionHeight;
162-
} else {
163-
descriptionEl.style.height = 'auto';
164-
}
165-
},
166-
},
167-
mounted: function () {
168-
if (this.tool.description) {
169-
this.computeDescriptionHeight();
170-
} else {
171-
this.needShowMore = false;
172-
this.showMore = false;
173142
}
174143
},
175144
};

0 commit comments

Comments
 (0)