···78787979
80808181-- Any paragraphs, except the first one, with more than 3 hashtags will be collapsed.
8181+- First paragraph of post content with more than 3 hashtags will be collapsed to max 3 lines.
8282+- Subsequent paragraphs after first paragraph with more than 3 hashtags will be collapsed to 1 line.
8383+- Adjacent paragraphs with more than 1 hashtag after collapsed paragraphs will be collapsed to 1 line.
8284- If there are text around or between the hashtags, they will not be collapsed.
8383-- Collapsed hashtags will be a single line with `...` at the end.
8585+- Collapsed hashtags will be appended with `...` at the end.
8486- They are also slightly faded out to reduce visual noise.
8587- Opening the post view will reveal the hashtags uncollapsed.
8688
+39-25
src/utils/enhance-content.js
···174174 // ================
175175 // Get the <p> that contains a lot of hashtags, add a class to it
176176 if (enhancedContent.indexOf('#') !== -1) {
177177- const hashtagStuffedParagraph = Array.from(dom.querySelectorAll('p')).find(
178178- (p) => {
179179- let hashtagCount = 0;
180180- for (let i = 0; i < p.childNodes.length; i++) {
181181- const node = p.childNodes[i];
177177+ let prevIndex = null;
178178+ const hashtagStuffedParagraphs = Array.from(
179179+ dom.querySelectorAll('p'),
180180+ ).filter((p, index) => {
181181+ let hashtagCount = 0;
182182+ for (let i = 0; i < p.childNodes.length; i++) {
183183+ const node = p.childNodes[i];
182184183183- if (node.nodeType === Node.TEXT_NODE) {
184184- const text = node.textContent.trim();
185185- if (text !== '') {
186186- return false;
187187- }
188188- } else if (node.tagName === 'A') {
189189- const linkText = node.textContent.trim();
190190- if (!linkText || !linkText.startsWith('#')) {
191191- return false;
192192- } else {
193193- hashtagCount++;
194194- }
195195- } else {
185185+ if (node.nodeType === Node.TEXT_NODE) {
186186+ const text = node.textContent.trim();
187187+ if (text !== '') {
196188 return false;
197189 }
190190+ } else if (node.tagName === 'BR') {
191191+ // Ignore <br />
192192+ } else if (node.tagName === 'A') {
193193+ const linkText = node.textContent.trim();
194194+ if (!linkText || !linkText.startsWith('#')) {
195195+ return false;
196196+ } else {
197197+ hashtagCount++;
198198+ }
199199+ } else {
200200+ return false;
198201 }
199199- // Only consider "stuffing" if there are more than 3 hashtags
200200- return hashtagCount > 3;
201201- },
202202- );
203203- if (hashtagStuffedParagraph) {
204204- hashtagStuffedParagraph.classList.add('hashtag-stuffing');
205205- hashtagStuffedParagraph.title = hashtagStuffedParagraph.innerText;
202202+ }
203203+ // Only consider "stuffing" if:
204204+ // - there are more than 3 hashtags
205205+ // - there are more than 1 hashtag in adjacent paragraphs
206206+ if (hashtagCount > 3) {
207207+ prevIndex = index;
208208+ return true;
209209+ }
210210+ if (hashtagCount > 1 && prevIndex && index === prevIndex + 1) {
211211+ prevIndex = index;
212212+ return true;
213213+ }
214214+ });
215215+ if (hashtagStuffedParagraphs?.length) {
216216+ hashtagStuffedParagraphs.forEach((p) => {
217217+ p.classList.add('hashtag-stuffing');
218218+ p.title = p.innerText;
219219+ });
206220 }
207221 }
208222