[READ-ONLY] Mirror of https://github.com/improsocial/impro An extensible Bluesky client for web impro.social
6

Configure Feed

Select the types of activity you want to include in your feed.

Truncate long URLs in rich text

Grace Kind (Apr 4, 2026, 3:08 PM -0500) 601b4b9e 8945da82

+66 -2
+1 -1
package.json
··· 1 1 { 2 2 "name": "impro", 3 - "version": "0.9.30", 3 + "version": "0.9.31", 4 4 "type": "module", 5 5 "scripts": { 6 6 "start": "rm -rf build && NODE_ENV=development eleventy --serve",
+21 -1
src/js/templates/richText.template.js
··· 5 5 6 6 const KNOWN_UNSUPPORTED_FACET_TYPES = ["blue.poll.post.facet#option"]; 7 7 8 + // Matches social-app behavior 9 + export function truncateUrl(url) { 10 + try { 11 + const urlp = new URL(url); 12 + if (urlp.protocol !== "http:" && urlp.protocol !== "https:") { 13 + return url; 14 + } 15 + const path = 16 + (urlp.pathname === "/" ? "" : urlp.pathname) + urlp.search + urlp.hash; 17 + if (path.length > 15) { 18 + return urlp.host + path.slice(0, 13) + "..."; 19 + } 20 + return urlp.host + path; 21 + } catch { 22 + return url; 23 + } 24 + } 25 + 8 26 function facetTemplate({ facet, wrappedText }) { 9 27 // only support 1 feature for now 10 28 const feature = facet.features[0]; ··· 15 33 switch (feature.$type) { 16 34 case "app.bsky.richtext.facet#link": 17 35 const uri = feature.uri; 18 - return html`<a href="${sanitizeUri(uri)}">${wrappedText}</a>`; 36 + return html`<a href="${sanitizeUri(uri)}" 37 + >${truncateUrl(wrappedText)}</a 38 + >`; 19 39 case "app.bsky.richtext.facet#tag": 20 40 const tag = feature.tag; 21 41 return html`<a href="${linkToHashtag(tag)}">${wrappedText}</a>`;
+44
tests/unit/specs/templates/richText.template.test.js
··· 40 40 assertEquals(link.textContent, "example.com"); 41 41 }); 42 42 43 + it("should truncate long link text", () => { 44 + const url = "https://example.com/very/long/path/to/page"; 45 + const text = "See " + url; 46 + const facets = [ 47 + { 48 + index: { byteStart: 4, byteEnd: 4 + url.length }, 49 + features: [ 50 + { 51 + $type: "app.bsky.richtext.facet#link", 52 + uri: url, 53 + }, 54 + ], 55 + }, 56 + ]; 57 + const result = richTextTemplate({ text, facets }); 58 + const container = document.createElement("div"); 59 + render(result, container); 60 + const link = container.querySelector("a"); 61 + assert(link !== null); 62 + assertEquals(link.getAttribute("href"), url); 63 + assertEquals(link.textContent, "example.com/very/long/pa..."); 64 + }); 65 + 66 + it("should not truncate short link text", () => { 67 + const url = "https://example.com/short"; 68 + const text = "See " + url; 69 + const facets = [ 70 + { 71 + index: { byteStart: 4, byteEnd: 4 + url.length }, 72 + features: [ 73 + { 74 + $type: "app.bsky.richtext.facet#link", 75 + uri: url, 76 + }, 77 + ], 78 + }, 79 + ]; 80 + const result = richTextTemplate({ text, facets }); 81 + const container = document.createElement("div"); 82 + render(result, container); 83 + const link = container.querySelector("a"); 84 + assertEquals(link.textContent, "example.com/short"); 85 + }); 86 + 43 87 it("should render text with mention facet", () => { 44 88 const text = "Hello @user"; 45 89 const facets = [