Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

news: visually distinguish external (Bluesky) headlines

- news-row--external and news-item--external modifier classes
- left accent bar in a Bluesky blue + faint tint so external posts
stand out at a glance from AC-authored ones
- handle + badge recolored with the same palette
- item page shows an 'original' link next to the date when the post
came in via an external source

+90 -16
+17 -10
system/netlify/functions/news.mjs
··· 552 552 } catch { return ""; } 553 553 })() : ""; 554 554 const itemUrl = `${basePath}/${post.code}`; 555 + const ext = post.externalAttribution; 556 + const rowClass = ext ? `news-row news-row--external news-row--external-${escapeHtml(ext.source || 'bsky')}` : "news-row"; 555 557 return ` 556 - <div class="news-row"> 558 + <div class="${rowClass}"${ext ? ` data-external-source="${escapeHtml(ext.source || 'bsky')}"` : ""}> 557 559 <div class="news-rank">${idx + 1}.</div> 558 560 <div class="news-content"> 559 561 <div class="news-title"> ··· 561 563 ${displayUrl ? `<span class="news-domain">(<a href="${url}" target="_blank" rel="noreferrer">${displayUrl}</a>)</span>` : ""} 562 564 </div> 563 565 <div class="news-meta"> 564 - <span>by ${renderHandle(post.handle, post.externalAttribution ? { 566 + <span>by ${renderHandle(post.handle, ext ? { 565 567 external: true, 566 - profileUrl: post.externalAttribution.profileUrl, 567 - sourceLabel: post.externalAttribution.sourceLabel, 568 + profileUrl: ext.profileUrl, 569 + sourceLabel: ext.sourceLabel, 568 570 } : undefined)}</span> 569 571 <span><a href="${itemUrl}">${formatDate(post.when)}</a></span> 570 572 <span><a href="${itemUrl}">${post.commentCount || 0} comments</a></span> ··· 860 862 const hasMedia = youtubeId || kidlispCode || acPiece || imgurUrl || directImageUrl || efluxPreviewHtml || instagramPreviewHtml || ogPreviewHtml; 861 863 const mediaHtml = youtubeEmbedHtml || kidlispPreviewHtml || acPreviewHtml || imgurPreviewHtml || directImagePreviewHtml || efluxPreviewHtml || instagramPreviewHtml || ogPreviewHtml; 862 864 865 + const itemExt = hydratedPost.externalAttribution; 866 + const mainClass = itemExt 867 + ? `news-main news-item--external news-item--external-${escapeHtml(itemExt.source || 'bsky')}` 868 + : "news-main"; 869 + 863 870 const body = ` 864 871 ${header(basePath)} 865 872 ${hasMedia ? `<div class="news-hero-media"> 866 873 ${mediaHtml} 867 874 </div>` : ''} 868 - <main class="news-main"> 875 + <main class="${mainClass}"${itemExt ? ` data-external-source="${escapeHtml(itemExt.source || 'bsky')}"` : ""}> 869 876 <div class="news-item-header"> 870 877 <div class="news-item-info"> 871 878 <table class="news-item-table" border="0" cellpadding="0" cellspacing="0"> ··· 890 897 </div> 891 898 </div> 892 899 ${hydratedPost.text ? ` 893 - <div class="news-op-text"> 894 - <div class="news-op-meta">${renderHandle(hydratedPost.handle, hydratedPost.externalAttribution ? { 900 + <div class="news-op-text${itemExt ? ' news-op-text--external' : ''}"> 901 + <div class="news-op-meta">${renderHandle(hydratedPost.handle, itemExt ? { 895 902 external: true, 896 - profileUrl: hydratedPost.externalAttribution.profileUrl, 897 - sourceLabel: hydratedPost.externalAttribution.sourceLabel, 898 - } : undefined)} ${formatDate(hydratedPost.when)}</div> 903 + profileUrl: itemExt.profileUrl, 904 + sourceLabel: itemExt.sourceLabel, 905 + } : undefined)} ${formatDate(hydratedPost.when)}${itemExt?.postUrl ? ` · <a href="${escapeHtml(itemExt.postUrl)}" class="news-external-original" target="_blank" rel="noopener">original</a>` : ""}</div> 899 906 <div class="news-op-body">${renderMarkdown(hydratedPost.text)}</div> 900 907 </div>` : ""} 901 908 <div class="news-comments">
+73 -6
system/public/news.aesthetic.computer/main.css
··· 455 455 text-decoration: underline; 456 456 } 457 457 458 - /* External-source attribution (e.g. Bluesky) */ 458 + /* ========================================================================= 459 + External-source posts (e.g. Bluesky @artistnewsnetwork). 460 + Visually distinct from AC-authored headlines: tinted left accent bar, 461 + bsky-blue handle, lowercase "bsky" badge next to the handle. 462 + ========================================================================= */ 463 + 464 + /* Per-source palette. Defaults to Bluesky blue; add new sources here. */ 465 + :root { 466 + --external-bsky: #2088ff; 467 + --external-bsky-tint: rgba(32, 136, 255, 0.08); 468 + --external-bsky-edge: rgba(32, 136, 255, 0.55); 469 + } 470 + 471 + /* --- Row on the list page ----------------------------------------------- */ 472 + .news-row--external { 473 + position: relative; 474 + padding-left: 8px; 475 + border-left: 3px solid var(--external-bsky-edge); 476 + background: var(--external-bsky-tint); 477 + border-radius: 0 3px 3px 0; 478 + } 479 + 480 + .news-row--external .news-title a { 481 + color: var(--text-link); 482 + } 483 + 484 + .news-row--external .news-rank { 485 + color: var(--external-bsky-edge); 486 + } 487 + 488 + /* --- Item page main container ------------------------------------------- */ 489 + .news-item--external { 490 + border-left: 3px solid var(--external-bsky-edge); 491 + padding-left: 10px; 492 + background: linear-gradient( 493 + to right, 494 + var(--external-bsky-tint) 0%, 495 + transparent 240px 496 + ); 497 + } 498 + 499 + .news-op-text--external { 500 + border-left: 2px solid var(--external-bsky-edge); 501 + padding-left: 10px; 502 + margin-left: -2px; 503 + } 504 + 505 + /* --- Handle link ("@artistnewsnetwork") --------------------------------- */ 506 + .news-handle-link.news-external-handle { 507 + color: var(--external-bsky); 508 + } 509 + .news-handle-link.news-external-handle:hover { 510 + color: var(--external-bsky); 511 + text-decoration: underline; 512 + } 513 + 514 + /* --- Source badge ("bsky") next to the handle --------------------------- */ 459 515 .news-external-badge { 460 516 display: inline-block; 461 517 margin-left: 4px; 462 - padding: 0 4px; 518 + padding: 0 5px; 463 519 font-size: 0.7em; 464 520 font-weight: normal; 465 521 text-transform: uppercase; 466 - letter-spacing: 0.04em; 467 - border: 1px solid currentColor; 522 + letter-spacing: 0.05em; 523 + color: var(--external-bsky); 524 + border: 1px solid var(--external-bsky-edge); 468 525 border-radius: 3px; 469 - opacity: 0.65; 526 + background: var(--external-bsky-tint); 470 527 vertical-align: 1px; 528 + opacity: 0.9; 471 529 } 472 530 531 + /* --- "via @handle · original" on the item page -------------------------- */ 473 532 .news-external-attrib { 474 - opacity: 0.75; 533 + opacity: 0.8; 475 534 font-size: 0.9em; 476 535 margin-right: 8px; 536 + } 537 + 538 + .news-external-original { 539 + color: var(--external-bsky); 540 + text-decoration: none; 541 + } 542 + .news-external-original:hover { 543 + text-decoration: underline; 477 544 } 478 545 479 546 /* ===== Item Page (HN-style table layout) ===== */