this repo has no description
2
fork

Configure Feed

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

fix: embed logos as base64 data URIs to fix broken images in GitHub

Agent-Logs-Url: https://github.com/nove-b/tangled-activity/sessions/5f80b035-ce21-4c85-837b-059131bb90ec

Co-authored-by: nove-b <68768186+nove-b@users.noreply.github.com>

authored by

copilot-swe-agent[bot]
nove-b
and committed by
GitHub
6eca62a2 884aaa6d

+44 -6
+18 -1
api/graph.ts
··· 4 4 buildGraphSvg, 5 5 clampRange, 6 6 fetchActivityByDay, 7 + fetchLogoDataUri, 7 8 normalizeAccount, 8 9 } from '../src/tangledGraph'; 10 + 11 + const LOGO_URL_LIGHT = 'https://assets.tangled.network/tangled_logotype_black_on_trans.svg'; 12 + const LOGO_URL_DARK = 'https://assets.tangled.network/tangled_logotype_white_on_trans.svg'; 9 13 10 14 export default async function handler( 11 15 req: VercelRequest, ··· 36 40 return; 37 41 } 38 42 43 + const [logoLightDataUri, logoDarkDataUri] = await Promise.all([ 44 + fetchLogoDataUri(LOGO_URL_LIGHT), 45 + fetchLogoDataUri(LOGO_URL_DARK), 46 + ]); 47 + 39 48 try { 40 49 const days = await fetchActivityByDay(account, range); 41 - res.status(200).send(buildGraphSvg({ account, range, days })); 50 + res.status(200).send(buildGraphSvg({ 51 + account, 52 + range, 53 + days, 54 + logoLightDataUri, 55 + logoDarkDataUri, 56 + })); 42 57 } catch (error) { 43 58 const message = error instanceof Error ? error.message : 'Failed to load feed'; 44 59 res.status(502).send( ··· 47 62 range, 48 63 days: [], 49 64 error: message, 65 + logoLightDataUri, 66 + logoDarkDataUri, 50 67 }), 51 68 ); 52 69 }
+26 -5
src/tangledGraph.ts
··· 17 17 range: number; 18 18 days: HeatmapDay[]; 19 19 error?: string; 20 + logoLightDataUri?: string; 21 + logoDarkDataUri?: string; 20 22 }; 21 23 22 24 type ParsedFeed = { ··· 103 105 return buildDays(counts, rangeStart, calendarStart, now); 104 106 } 105 107 106 - export function buildGraphSvg({ account, range, days, error }: GraphSvgOptions): string { 108 + export async function fetchLogoDataUri(url: string): Promise<string | undefined> { 109 + try { 110 + const response = await fetch(url, { 111 + headers: { 'User-Agent': 'tangled-activity-graph' }, 112 + }); 113 + if (!response.ok) { 114 + return undefined; 115 + } 116 + const contentType = response.headers.get('content-type') ?? 'image/svg+xml'; 117 + const buffer = await response.arrayBuffer(); 118 + const base64 = Buffer.from(buffer).toString('base64'); 119 + return `data:${contentType};base64,${base64}`; 120 + } catch { 121 + return undefined; 122 + } 123 + } 124 + 125 + export function buildGraphSvg({ account, range, days, error, logoLightDataUri, logoDarkDataUri }: GraphSvgOptions): string { 107 126 const weekCount = days.length === 0 ? 1 : Math.max(...days.map((day) => day.weekIndex)) + 1; 108 127 const graphWidth = weekCount * (CELL_SIZE + CELL_GAP) - CELL_GAP; 109 128 const graphHeight = 7 * (CELL_SIZE + CELL_GAP) - CELL_GAP; ··· 213 232 ${weekdays} 214 233 ${rects} 215 234 ${summary} 216 - ${renderLogo(width, height)} 235 + ${renderLogo(width, height, logoLightDataUri, logoDarkDataUri)} 217 236 </a> 218 237 </svg>`; 219 238 } ··· 326 345 return 4; 327 346 } 328 347 329 - function renderLogo(width: number, height: number): string { 348 + function renderLogo(width: number, height: number, logoLightDataUri?: string, logoDarkDataUri?: string): string { 330 349 const x = width - RIGHT_GUTTER - LOGO_WIDTH; 331 350 const y = height - FOOTER_HEIGHT + 1; 351 + const lightSrc = logoLightDataUri ?? LOGO_URL_LIGHT; 352 + const darkSrc = logoDarkDataUri ?? LOGO_URL_DARK; 332 353 333 354 return ( 334 - `<image class="logo-light" x="${x}" y="${y}" width="${LOGO_WIDTH}" height="${LOGO_HEIGHT}" href="${LOGO_URL_LIGHT}" />` + 335 - `<image class="logo-dark" x="${x}" y="${y}" width="${LOGO_WIDTH}" height="${LOGO_HEIGHT}" href="${LOGO_URL_DARK}" />` 355 + `<image class="logo-light" x="${x}" y="${y}" width="${LOGO_WIDTH}" height="${LOGO_HEIGHT}" href="${lightSrc}" />` + 356 + `<image class="logo-dark" x="${x}" y="${y}" width="${LOGO_WIDTH}" height="${LOGO_HEIGHT}" href="${darkSrc}" />` 336 357 ); 337 358 } 338 359