Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

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

sotce-net: fix Q&A font size, question numbering, respond editor UX

- Question text now same font size as answer (was 0.9x smaller)
- Question page numbers count up chronologically (assigned after sort)
- Respond editor shows relative time: 'asked by @handle 3 days ago'
- Nav counter between prev/next buttons: '2 / 5'

+39 -9
+39 -9
system/netlify/functions/sotce-net.mjs
··· 5490 5490 linesLeft.id = "respond-lines-left"; 5491 5491 const totalPageLines = 19; // Max lines available for question + answer 5492 5492 5493 - // Asked by indicator (top right) 5493 + // Asked by indicator (top left) 5494 5494 const askedBy = cel("div"); 5495 5495 askedBy.id = "respond-asked-by"; 5496 5496 let maxRespondLines = 12; // Will be calculated per question ··· 5498 5498 let lastValidValue = ""; 5499 5499 let responseWords = null; 5500 5500 5501 + // Relative time helper (e.g. "3 days ago") 5502 + function timeAgo(date) { 5503 + const now = new Date(); 5504 + const d = (typeof date === "string") ? new Date(date) : date; 5505 + const seconds = Math.floor((now - d) / 1000); 5506 + if (seconds < 60) return "just now"; 5507 + const minutes = Math.floor(seconds / 60); 5508 + if (minutes < 60) return minutes + (minutes === 1 ? " minute ago" : " minutes ago"); 5509 + const hours = Math.floor(minutes / 60); 5510 + if (hours < 24) return hours + (hours === 1 ? " hour ago" : " hours ago"); 5511 + const days = Math.floor(hours / 24); 5512 + if (days < 30) return days + (days === 1 ? " day ago" : " days ago"); 5513 + const months = Math.floor(days / 30); 5514 + if (months < 12) return months + (months === 1 ? " month ago" : " months ago"); 5515 + const years = Math.floor(months / 12); 5516 + return years + (years === 1 ? " year ago" : " years ago"); 5517 + } 5518 + 5501 5519 function renderRespondPage() { 5502 5520 respondPage.innerHTML = ""; 5503 5521 ··· 5511 5529 } 5512 5530 5513 5531 const question = pendingData[currentPendingIndex]; 5532 + const ago = question.when ? " " + timeAgo(question.when) : ""; 5514 5533 5515 - // Update asked-by indicator 5534 + // Update asked-by indicator with relative time 5516 5535 if (question.handle) { 5517 - askedBy.innerHTML = "asked by <span class='asked-by-handle'>@" + question.handle + "</span>"; 5536 + askedBy.innerHTML = "asked by <span class='asked-by-handle'>@" + question.handle + "</span>" + ago; 5518 5537 askedBy.style.display = "block"; 5519 5538 } else { 5520 - askedBy.innerText = "asked anonymously"; 5539 + askedBy.innerText = "asked anonymously" + ago; 5521 5540 askedBy.style.display = "block"; 5522 5541 } 5523 5542 ··· 5682 5701 5683 5702 const prevBtn = cel("button"); 5684 5703 prevBtn.innerText = "← prev"; 5704 + 5705 + const navCounter = cel("span"); 5706 + navCounter.id = "respond-nav-counter"; 5707 + navCounter.style.cssText = "opacity:0.6;font-size:0.85em;align-self:center;white-space:nowrap;"; 5685 5708 5686 5709 const nextBtn = cel("button"); 5687 5710 nextBtn.innerText = "next →"; ··· 5699 5722 nextBtn.disabled = !hasNext; 5700 5723 prevBtn.style.display = (pendingData && pendingData.length > 1) ? "" : "none"; 5701 5724 nextBtn.style.display = (pendingData && pendingData.length > 1) ? "" : "none"; 5725 + navCounter.style.display = (pendingData && pendingData.length > 1) ? "" : "none"; 5726 + if (pendingData && pendingData.length > 1) { 5727 + navCounter.innerText = (currentPendingIndex + 1) + " / " + pendingData.length; 5728 + } 5702 5729 if (!pendingData || pendingData.length === 0) { 5703 5730 submitBtn.disabled = true; 5704 5731 } else { ··· 5747 5774 5748 5775 nav.appendChild(nevermindBtn); 5749 5776 nav.appendChild(prevBtn); 5777 + nav.appendChild(navCounter); 5750 5778 nav.appendChild(nextBtn); 5751 5779 nav.appendChild(submitBtn); 5752 5780 ··· 6371 6399 }); 6372 6400 6373 6401 // Add questions with type marker 6374 - let questionNum = 1; 6375 6402 for (const q of loadedQuestionsData) { 6376 6403 feedItems.push({ 6377 6404 ...q, 6378 6405 type: "question", 6379 - questionNumber: questionNum++, 6380 6406 sortDate: new Date(q.answeredAt) 6381 6407 }); 6382 6408 } ··· 6384 6410 // Sort combined feed by date (newest last for chronological order) 6385 6411 feedItems.sort((a, b) => a.sortDate - b.sortDate); 6386 6412 6387 - // Assign feed indices (1-indexed) 6413 + // Assign feed indices (1-indexed) and question numbers (chronological) 6414 + let questionNum = 1; 6388 6415 feedItems.forEach((item, i) => { 6389 6416 item.feedIndex = i + 1; 6417 + if (item.type === "question") { 6418 + item.questionNumber = questionNum++; 6419 + } 6390 6420 }); 6391 6421 6392 6422 const totalFeedItems = totalPages + totalQuestions; ··· 6849 6879 ctx.textAlign = "left"; 6850 6880 } 6851 6881 6852 - // Header: question text (smaller, regular weight) 6882 + // Header: question text (same size as answer) 6853 6883 const headerY = y + h * 0.15 + fontSize; 6854 - const headerFont = (fontSize * 0.9) + "px Helvetica, sans-serif"; 6884 + const headerFont = fontSize + "px Helvetica, sans-serif"; 6855 6885 ctx.font = headerFont; // Set font BEFORE measuring for correct wrapping 6856 6886 ctx.textAlign = "left"; 6857 6887