Coffee journaling on ATProto (alpha) alpha.arabica.social
coffee
17
fork

Configure Feed

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

fix: feed card rotation amount and "load more"

+26 -17
+2 -2
internal/web/components/layout.templ
··· 115 115 <link rel="icon" href="/static/favicon.svg" type="image/svg+xml"/> 116 116 <link rel="icon" href="/static/favicon-32.svg" type="image/svg+xml" sizes="32x32"/> 117 117 <link rel="apple-touch-icon" href="/static/icon-192.svg"/> 118 - <link rel="stylesheet" href="/static/css/output.css?v=0.9.1"/> 118 + <link rel="stylesheet" href="/static/css/output.css?v=0.9.2"/> 119 119 <style> 120 120 [x-cloak] { display: none !important; } 121 121 </style> ··· 303 303 <script src="/static/js/entity-helpers.js?v=0.8.0"></script> 304 304 <script src="/static/js/data-cache.js?v=0.3.0"></script> 305 305 <script src="/static/js/sw-register.js?v=0.2.0"></script> 306 - <script src="/static/js/feed-masonry.js?v=0.1.0"></script> 306 + <script src="/static/js/feed-masonry.js?v=0.1.1"></script> 307 307 </head> 308 308 if tp := bff.Traceparent(ctx); tp != "" { 309 309 <meta name="traceparent" content={ tp }/>
+7 -8
static/css/app.css
··· 847 847 box-shadow: var(--shadow-md); 848 848 } 849 849 850 - /* Sticky-note rotation only inside the feed pinboard */ 850 + /* Sticky-note rotation only inside the feed pinboard. 851 + Uses the independent `rotate` property so it doesn't conflict 852 + with the fade-in-slide-up animation's `transform`. */ 851 853 @media (min-width: 768px) { 852 854 .feed-grid .feed-card { 853 - transform: rotate(var(--card-rotate, 0deg)); 855 + rotate: var(--card-rotate, 0deg); 854 856 backface-visibility: hidden; 855 857 } 856 858 857 859 .feed-grid .feed-card:hover { 858 - transform: rotate(0deg) translateY(-2px); 860 + rotate: 0deg; 861 + transform: translateY(-2px); 859 862 } 860 863 861 - .feed-grid .feed-card:nth-child(5n+1) { --card-rotate: -0.8deg; } 862 - .feed-grid .feed-card:nth-child(5n+2) { --card-rotate: 0.5deg; } 863 - .feed-grid .feed-card:nth-child(5n+3) { --card-rotate: -0.3deg; } 864 - .feed-grid .feed-card:nth-child(5n+4) { --card-rotate: 0.7deg; } 865 - .feed-grid .feed-card:nth-child(5n+5) { --card-rotate: 0deg; } 864 + /* --card-rotate values are assigned per-card via JS in feed-masonry.js */ 866 865 } 867 866 868 867 /* Brew cards — the main sticky note, slightly larger presence */
+17 -7
static/js/feed-masonry.js
··· 19 19 return cards; 20 20 } 21 21 22 + // Assign a random subtle rotation to a card (sticky-note effect) 23 + var ROTATIONS = [-0.8, -0.5, -0.3, 0, 0.3, 0.5, 0.7]; 24 + function assignRotation(card) { 25 + if (!card.style.getPropertyValue('--card-rotate')) { 26 + var deg = ROTATIONS[Math.floor(Math.random() * ROTATIONS.length)]; 27 + card.style.setProperty('--card-rotate', deg + 'deg'); 28 + } 29 + } 30 + 22 31 // Distribute loose cards into two masonry columns (shortest-first) 23 32 function masonryLayout(container) { 24 33 var cards = getLooseCards(container); ··· 38 47 39 48 var heights = [cols[0].offsetHeight, cols[1].offsetHeight]; 40 49 cards.forEach(function (card) { 50 + assignRotation(card); 41 51 var idx = heights[0] <= heights[1] ? 0 : 1; 42 52 cols[idx].appendChild(card); 43 53 heights[idx] += card.offsetHeight + 20; ··· 49 59 var cols = container.querySelectorAll(':scope > .feed-masonry-col'); 50 60 if (cols.length === 0) return; 51 61 52 - // Interleave from both columns to restore chronological order 53 62 var c0 = cols[0] ? Array.from(cols[0].children) : []; 54 63 var c1 = cols[1] ? Array.from(cols[1].children) : []; 55 64 var merged = []; ··· 59 68 if (i < c1.length) merged.push(c1[i]); 60 69 } 61 70 62 - // Find insertion point (before first non-column, non-card child like load-more) 63 71 var ref = null; 64 72 for (var j = 0; j < container.children.length; j++) { 65 73 var ch = container.children[j]; ··· 96 104 // Viewport changes 97 105 MQ.addEventListener('change', applyLayout); 98 106 99 - // After HTMX swaps (load-more, filter/sort changes) 100 - document.addEventListener('htmx:afterSettle', function (e) { 101 - var t = e.detail.target; 102 - if (t && (t.id === 'feed-items' || (t.closest && t.closest('#feed-items')))) { 107 + // After any HTMX swap, check if feed has loose cards to distribute. 108 + // Uses requestAnimationFrame so new DOM has dimensions for height measurement. 109 + document.addEventListener('htmx:afterSettle', function () { 110 + var container = getContainer(); 111 + if (!container) return; 112 + requestAnimationFrame(function () { 103 113 applyLayout(); 104 - } 114 + }); 105 115 }); 106 116 })();