this repo has no description
2
fork

Configure Feed

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

feat: add system color mode support with dark/light logo switching

Agent-Logs-Url: https://github.com/nove-b/tangled-activity/sessions/ad7c5536-c65f-429a-9243-747be94ba1d2

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

authored by

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

+64 -12
+64 -12
src/tangledGraph.ts
··· 38 38 const HEADER_TITLE_Y = 53; 39 39 const LOGO_WIDTH = 140; 40 40 const LOGO_HEIGHT = 24; 41 - const LOGO_URL = 'https://assets.tangled.network/tangled_logotype_black_on_trans.svg'; 41 + const LOGO_URL_LIGHT = 'https://assets.tangled.network/tangled_logotype_black_on_trans.svg'; 42 + const LOGO_URL_DARK = 'https://assets.tangled.network/tangled_logotype_white_on_trans.svg'; 42 43 const MIN_CANVAS_WIDTH = 700; 43 44 const HEADER_CHAR_WIDTH = 8.2; 44 45 const SUMMARY_CHAR_WIDTH = 6.2; ··· 48 49 { label: 'Fri', row: 5 }, 49 50 ]; 50 51 const MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 51 - const HEATMAP_COLORS = ['#ebedf0', '#d1d5db', '#9ca3af', '#4b5563', '#111827'] as const; 52 52 53 53 export function normalizeAccount(input: string | undefined): string | null { 54 54 if (!input) { ··· 127 127 .map((day) => { 128 128 const x = LEFT_GUTTER + day.weekIndex * (CELL_SIZE + CELL_GAP); 129 129 const y = graphStartY + day.weekdayIndex * (CELL_SIZE + CELL_GAP); 130 - const fill = day.inRange ? HEATMAP_COLORS[day.level] : '#f8fafc'; 131 - const stroke = day.inRange ? 'none' : '#e5e7eb'; 130 + const cellClass = day.inRange ? `heat-${day.level}` : 'oor'; 132 131 const tooltip = `${day.isoDate}: ${day.count} activit${day.count === 1 ? 'y' : 'ies'}`; 133 132 134 - return `<g><title>${escapeXml(tooltip)}</title><rect x="${x}" y="${y}" width="${CELL_SIZE}" height="${CELL_SIZE}" rx="2" fill="${fill}" stroke="${stroke}" /></g>`; 133 + return `<g><title>${escapeXml(tooltip)}</title><rect x="${x}" y="${y}" width="${CELL_SIZE}" height="${CELL_SIZE}" rx="2" class="${cellClass}" /></g>`; 135 134 }) 136 135 .join(''); 137 136 138 137 const weekdays = WEEKDAY_LABELS.map(({ label, row }) => { 139 138 const y = graphStartY + row * (CELL_SIZE + CELL_GAP) + CELL_SIZE - 1; 140 - return `<text x="8" y="${y}" font-size="10" fill="#6b7280">${label}</text>`; 139 + return `<text x="8" y="${y}" font-size="10" class="label">${label}</text>`; 141 140 }).join(''); 142 141 143 142 const months = monthLabels 144 143 .map(({ label, weekIndex }) => { 145 144 const x = LEFT_GUTTER + weekIndex * (CELL_SIZE + CELL_GAP); 146 - return `<text x="${x}" y="${graphStartY - MONTH_LABEL_OFFSET}" font-size="10" fill="#6b7280">${label}</text>`; 145 + return `<text x="${x}" y="${graphStartY - MONTH_LABEL_OFFSET}" font-size="10" class="label">${label}</text>`; 147 146 }) 148 147 .join(''); 149 148 150 149 const summary = error 151 - ? `<text x="${LEFT_GUTTER}" y="${height - 10}" font-size="11" fill="#b91c1c">${escapeXml(error)}</text>` 152 - : `<text x="${LEFT_GUTTER}" y="${height - 10}" font-size="11" fill="#4b5563">${escapeXml(summaryText)}</text>`; 150 + ? `<text x="${LEFT_GUTTER}" y="${height - 10}" font-size="11" class="error">${escapeXml(error)}</text>` 151 + : `<text x="${LEFT_GUTTER}" y="${height - 10}" font-size="11" class="summary">${escapeXml(summaryText)}</text>`; 153 152 const accountUrl = `https://tangled.org/@${encodeURIComponent(account)}`; 154 153 155 154 return `<?xml version="1.0" encoding="UTF-8"?> 156 155 <svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" preserveAspectRatio="xMinYMin meet" style="max-width:100%;height:auto" role="img" aria-labelledby="title desc"> 157 156 <title id="title">${escapeXml(headerText)}</title> 158 157 <desc id="desc">Calendar heatmap of Tangled activities for ${escapeXml(account)}</desc> 158 + <style> 159 + :root { 160 + --bg: #ffffff; 161 + --border: #e5e7eb; 162 + --title: #111827; 163 + --label: #6b7280; 164 + --summary: #4b5563; 165 + --error: #b91c1c; 166 + --heat-0: #ebedf0; 167 + --heat-1: #d1d5db; 168 + --heat-2: #9ca3af; 169 + --heat-3: #4b5563; 170 + --heat-4: #111827; 171 + --oor-fill: #f8fafc; 172 + --oor-stroke: #e5e7eb; 173 + } 174 + @media (prefers-color-scheme: dark) { 175 + :root { 176 + --bg: #161b22; 177 + --border: #30363d; 178 + --title: #e6edf3; 179 + --label: #8b949e; 180 + --summary: #8b949e; 181 + --error: #f85149; 182 + --heat-0: #21262d; 183 + --heat-1: #374151; 184 + --heat-2: #6b7280; 185 + --heat-3: #9ca3af; 186 + --heat-4: #e6edf3; 187 + --oor-fill: #0d1117; 188 + --oor-stroke: #21262d; 189 + } 190 + } 191 + .bg { fill: var(--bg); stroke: var(--border); } 192 + .title { fill: var(--title); } 193 + .label { fill: var(--label); } 194 + .summary { fill: var(--summary); } 195 + .error { fill: var(--error); } 196 + .heat-0 { fill: var(--heat-0); } 197 + .heat-1 { fill: var(--heat-1); } 198 + .heat-2 { fill: var(--heat-2); } 199 + .heat-3 { fill: var(--heat-3); } 200 + .heat-4 { fill: var(--heat-4); } 201 + .oor { fill: var(--oor-fill); stroke: var(--oor-stroke); } 202 + .logo-dark { display: none; } 203 + @media (prefers-color-scheme: dark) { 204 + .logo-light { display: none; } 205 + .logo-dark { display: block; } 206 + } 207 + </style> 159 208 <a href="${accountUrl}" target="_blank"> 160 - <rect width="100%" height="100%" rx="${CARD_RADIUS}" fill="#ffffff" stroke="#e5e7eb" /> 161 - <text x="${HEADER_TEXT_X}" y="${HEADER_TITLE_Y}" font-size="15" font-weight="600" fill="#111827">${escapeXml(headerText)}</text> 209 + <rect width="100%" height="100%" rx="${CARD_RADIUS}" class="bg" /> 210 + <text x="${HEADER_TEXT_X}" y="${HEADER_TITLE_Y}" font-size="15" font-weight="600" class="title">${escapeXml(headerText)}</text> 162 211 163 212 ${months} 164 213 ${weekdays} ··· 281 330 const x = width - RIGHT_GUTTER - LOGO_WIDTH; 282 331 const y = height - FOOTER_HEIGHT + 1; 283 332 284 - return `<image x="${x}" y="${y}" width="${LOGO_WIDTH}" height="${LOGO_HEIGHT}" href="${LOGO_URL}" />`; 333 + 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}" />` 336 + ); 285 337 } 286 338 287 339 function subtractUtcMonths(date: Date, months: number): Date {