this repo has no description
0
fork

Configure Feed

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

Enable on-demand posting stats

- Slight refactor
- Make sure stats also work when switching instances
- Make sure zero stats fallback

+231 -121
+69 -10
src/components/account-info.css
··· 342 342 opacity: 1; 343 343 } 344 344 } 345 - .account-container .posting-stats { 346 - font-size: 90%; 347 - color: var(--text-insignificant-color); 345 + .account-container .posting-stats-button { 346 + display: flex; 347 + align-items: center; 348 + justify-content: center; 349 + gap: 8px; 350 + width: 100%; 351 + color: inherit; 348 352 background-color: var(--bg-faded-color); 349 353 padding: 8px 12px; 350 - --size: 8px; 351 - --original-color: var(--link-color); 354 + font-size: 90%; 355 + color: var(--text-insignificant-color); 356 + line-height: 1; 357 + vertical-align: text-top; 358 + border-radius: 4px; 352 359 353 360 &:is(:hover, :focus-within) { 361 + color: var(--text-color); 354 362 background-color: var(--link-bg-hover-color); 363 + filter: none !important; 364 + } 365 + 366 + .loader-container { 367 + margin: 0; 368 + opacity: 0.5; 369 + transform: scale(0.75); 370 + } 371 + } 372 + 373 + @keyframes wobble { 374 + 0% { 375 + transform: rotate(-4deg); 376 + } 377 + 100% { 378 + transform: rotate(4deg); 379 + } 380 + } 381 + @keyframes loading-spin { 382 + 0% { 383 + transform: rotate(0deg) scale(0.75); 384 + } 385 + 100% { 386 + transform: rotate(360deg) scale(0.75); 387 + } 388 + } 389 + .posting-stats-icon { 390 + display: inline-block; 391 + width: 24px; 392 + height: 8px; 393 + filter: opacity(0.75); 394 + animation: wobble 2s linear both infinite alternate !important; 395 + 396 + &.loading { 397 + animation: loading-spin 0.35s linear both infinite !important; 398 + } 399 + } 400 + 401 + .account-container { 402 + --posting-stats-size: 8px; 403 + --original-color: var(--link-color); 404 + 405 + .posting-stats { 406 + font-size: 90%; 407 + color: var(--text-insignificant-color); 408 + background-color: var(--bg-faded-color); 409 + padding: 8px 12px; 410 + 411 + &:is(:hover, :focus-within) { 412 + background-color: var(--link-bg-hover-color); 413 + } 355 414 } 356 415 357 416 .posting-stats-bar { 358 417 --gap: 0.5px; 359 418 --gap-color: var(--outline-color); 360 - height: var(--size); 361 - border-radius: var(--size); 419 + height: var(--posting-stats-size); 420 + border-radius: var(--posting-stats-size); 362 421 overflow: hidden; 363 422 margin: 8px 0; 364 423 box-shadow: inset 0 0 0 1px var(--outline-color), ··· 388 447 389 448 .posting-stats-legend-item { 390 449 display: inline-block; 391 - width: var(--size); 392 - height: var(--size); 393 - border-radius: var(--size); 450 + width: var(--posting-stats-size); 451 + height: var(--posting-stats-size); 452 + border-radius: var(--posting-stats-size); 394 453 background-color: var(--text-insignificant-color); 395 454 vertical-align: middle; 396 455 margin: 0 4px 2px;
+162 -111
src/components/account-info.jsx
··· 206 206 207 207 const [familiarFollowers, setFamiliarFollowers] = useState([]); 208 208 const [postingStats, setPostingStats] = useState(); 209 - const hasPostingStats = postingStats?.total >= 3; 209 + const [postingStatsUIState, setPostingStatsUIState] = useState('default'); 210 + const hasPostingStats = !!postingStats?.total; 211 + const currentIDRef = useRef(); 210 212 211 - const onRelationshipChange = useCallback( 212 - ({ relationship, currentID }) => { 213 - if (!relationship.following) { 214 - (async () => { 215 - try { 216 - const fetchFamiliarFollowers = 217 - currentMasto.v1.accounts.familiarFollowers.fetch({ 218 - id: [currentID], 219 - }); 220 - const fetchStatuses = currentMasto.v1.accounts 221 - .$select(currentID) 222 - .statuses.list({ 223 - limit: 20, 224 - }) 225 - .next(); 213 + const renderFamiliarFollowers = async () => { 214 + if (!currentIDRef.current) return; 215 + const currentID = currentIDRef.current; 216 + try { 217 + const fetchFamiliarFollowers = 218 + currentMasto.v1.accounts.familiarFollowers.fetch({ 219 + id: [currentID], 220 + }); 226 221 227 - const followers = await fetchFamiliarFollowers; 228 - console.log('fetched familiar followers', followers); 229 - setFamiliarFollowers( 230 - followers[0].accounts.slice(0, FAMILIAR_FOLLOWERS_LIMIT), 231 - ); 222 + const followers = await fetchFamiliarFollowers; 223 + console.log('fetched familiar followers', followers); 224 + setFamiliarFollowers( 225 + followers[0].accounts.slice(0, FAMILIAR_FOLLOWERS_LIMIT), 226 + ); 227 + } catch (e) { 228 + console.error(e); 229 + } 230 + }; 232 231 233 - if (!standalone) { 234 - const { value: statuses } = await fetchStatuses; 235 - console.log('fetched statuses', statuses); 236 - const stats = { 237 - total: statuses.length, 238 - originals: 0, 239 - replies: 0, 240 - boosts: 0, 241 - }; 242 - // Categories statuses by type 243 - // - Original posts (not replies to others) 244 - // - Threads (self-replies + 1st original post) 245 - // - Boosts (reblogs) 246 - // - Replies (not-self replies) 247 - statuses.forEach((status) => { 248 - if (status.reblog) { 249 - stats.boosts++; 250 - } else if ( 251 - status.inReplyToAccountId !== currentID && 252 - !!status.inReplyToId 253 - ) { 254 - stats.replies++; 255 - } else { 256 - stats.originals++; 257 - } 258 - }); 232 + const renderPostingStats = async () => { 233 + setPostingStatsUIState('loading'); 234 + try { 235 + const fetchStatuses = masto.v1.accounts 236 + .$select(id) 237 + .statuses.list({ 238 + limit: 20, 239 + }) 240 + .next(); 259 241 260 - // Count days since last post 261 - stats.daysSinceLastPost = Math.ceil( 262 - (Date.now() - 263 - new Date(statuses[statuses.length - 1].createdAt)) / 264 - 86400000, 265 - ); 242 + const { value: statuses } = await fetchStatuses; 243 + console.log('fetched statuses', statuses); 244 + const stats = { 245 + total: statuses.length, 246 + originals: 0, 247 + replies: 0, 248 + boosts: 0, 249 + }; 250 + // Categories statuses by type 251 + // - Original posts (not replies to others) 252 + // - Threads (self-replies + 1st original post) 253 + // - Boosts (reblogs) 254 + // - Replies (not-self replies) 255 + statuses.forEach((status) => { 256 + if (status.reblog) { 257 + stats.boosts++; 258 + } else if (status.inReplyToAccountId !== id && !!status.inReplyToId) { 259 + stats.replies++; 260 + } else { 261 + stats.originals++; 262 + } 263 + }); 264 + 265 + // Count days since last post 266 + stats.daysSinceLastPost = Math.ceil( 267 + (Date.now() - new Date(statuses[statuses.length - 1].createdAt)) / 268 + 86400000, 269 + ); 270 + 271 + console.log('posting stats', stats); 272 + setPostingStats(stats); 273 + setPostingStatsUIState('default'); 274 + } catch (e) { 275 + console.error(e); 276 + setPostingStatsUIState('error'); 277 + } 278 + }; 266 279 267 - console.log('posting stats', stats); 268 - setPostingStats(stats); 269 - } 270 - } catch (e) { 271 - console.error(e); 272 - } 273 - })(); 280 + const onRelationshipChange = useCallback( 281 + ({ relationship, currentID }) => { 282 + currentIDRef.current = currentID; 283 + if (!relationship.following) { 284 + renderFamiliarFollowers(); 285 + if (!standalone) { 286 + renderPostingStats(); 287 + } 274 288 } 275 289 }, 276 290 [standalone], ··· 586 600 )} 587 601 </div> 588 602 </div> 589 - {hasPostingStats && ( 590 - <Link 603 + {!!postingStats && ( 604 + <LinkOrDiv 591 605 to={accountLink} 592 606 class="account-metadata-box" 593 607 onClick={() => { ··· 596 610 > 597 611 <div class="shazam-container"> 598 612 <div class="shazam-container-inner"> 599 - <div 600 - class="posting-stats" 601 - title={`${Math.round( 602 - (postingStats.originals / postingStats.total) * 100, 603 - )}% original posts, ${Math.round( 604 - (postingStats.replies / postingStats.total) * 100, 605 - )}% replies, ${Math.round( 606 - (postingStats.boosts / postingStats.total) * 100, 607 - )}% boosts`} 608 - > 609 - <div> 610 - {postingStats.daysSinceLastPost < 365 611 - ? `Last ${postingStats.total} posts in the past 612 - ${postingStats.daysSinceLastPost} day${ 613 - postingStats.daysSinceLastPost > 1 ? 's' : '' 614 - }` 615 - : ` 616 - Last ${postingStats.total} posts in the past year(s) 617 - `} 618 - </div> 613 + {hasPostingStats ? ( 619 614 <div 620 - class="posting-stats-bar" 621 - style={{ 622 - // [originals | replies | boosts] 623 - '--originals-percentage': `${ 624 - (postingStats.originals / postingStats.total) * 625 - 100 626 - }%`, 627 - '--replies-percentage': `${ 628 - ((postingStats.originals + postingStats.replies) / 629 - postingStats.total) * 630 - 100 631 - }%`, 632 - }} 633 - /> 634 - <div class="posting-stats-legends"> 635 - <span class="ib"> 636 - <span class="posting-stats-legend-item posting-stats-legend-item-originals" />{' '} 637 - Original 638 - </span>{' '} 639 - <span class="ib"> 640 - <span class="posting-stats-legend-item posting-stats-legend-item-replies" />{' '} 641 - Replies 642 - </span>{' '} 643 - <span class="ib"> 644 - <span class="posting-stats-legend-item posting-stats-legend-item-boosts" />{' '} 645 - Boosts 646 - </span> 615 + class="posting-stats" 616 + title={`${Math.round( 617 + (postingStats.originals / postingStats.total) * 100, 618 + )}% original posts, ${Math.round( 619 + (postingStats.replies / postingStats.total) * 100, 620 + )}% replies, ${Math.round( 621 + (postingStats.boosts / postingStats.total) * 100, 622 + )}% boosts`} 623 + > 624 + <div> 625 + {postingStats.daysSinceLastPost < 365 626 + ? `Last ${postingStats.total} posts in the past 627 + ${postingStats.daysSinceLastPost} day${ 628 + postingStats.daysSinceLastPost > 1 ? 's' : '' 629 + }` 630 + : ` 631 + Last ${postingStats.total} posts in the past year(s) 632 + `} 633 + </div> 634 + <div 635 + class="posting-stats-bar" 636 + style={{ 637 + // [originals | replies | boosts] 638 + '--originals-percentage': `${ 639 + (postingStats.originals / postingStats.total) * 640 + 100 641 + }%`, 642 + '--replies-percentage': `${ 643 + ((postingStats.originals + 644 + postingStats.replies) / 645 + postingStats.total) * 646 + 100 647 + }%`, 648 + }} 649 + /> 650 + <div class="posting-stats-legends"> 651 + <span class="ib"> 652 + <span class="posting-stats-legend-item posting-stats-legend-item-originals" />{' '} 653 + Original 654 + </span>{' '} 655 + <span class="ib"> 656 + <span class="posting-stats-legend-item posting-stats-legend-item-replies" />{' '} 657 + Replies 658 + </span>{' '} 659 + <span class="ib"> 660 + <span class="posting-stats-legend-item posting-stats-legend-item-boosts" />{' '} 661 + Boosts 662 + </span> 663 + </div> 647 664 </div> 648 - </div> 665 + ) : ( 666 + <div class="posting-stats">Post stats unavailable.</div> 667 + )} 649 668 </div> 650 669 </div> 651 - </Link> 670 + </LinkOrDiv> 652 671 )} 672 + <div class="account-metadata-box"> 673 + <div 674 + class="shazam-container no-animation" 675 + hidden={!!postingStats} 676 + > 677 + <div class="shazam-container-inner"> 678 + <button 679 + type="button" 680 + class="posting-stats-button" 681 + disabled={postingStatsUIState === 'loading'} 682 + onClick={() => { 683 + renderPostingStats(); 684 + }} 685 + > 686 + <div 687 + class={`posting-stats-bar posting-stats-icon ${ 688 + postingStatsUIState === 'loading' ? 'loading' : '' 689 + }`} 690 + style={{ 691 + '--originals-percentage': '33%', 692 + '--replies-percentage': '66%', 693 + }} 694 + /> 695 + View post stats{' '} 696 + {/* <Loader 697 + abrupt 698 + hidden={postingStatsUIState !== 'loading'} 699 + /> */} 700 + </button> 701 + </div> 702 + </div> 703 + </div> 653 704 <RelatedActions 654 705 info={info} 655 706 instance={instance}