diff --git a/src/components/account-info.css b/src/components/account-info.css index 168c4841..197a0579 100644 --- a/src/components/account-info.css +++ b/src/components/account-info.css @@ -139,13 +139,13 @@ /* flex-wrap: wrap; */ column-gap: 24px; row-gap: 8px; - opacity: 0.75; + /* opacity: 0.75; */ font-size: 90%; background-color: var(--bg-faded-color); padding: 12px; - border-radius: 16px; + /* border-radius: 16px; */ line-height: 1.25; - overflow-x: auto; + overflow-x: auto !important; justify-content: flex-start; position: relative; @@ -185,11 +185,33 @@ display: flex; } +.account-container .account-metadata-box { + overflow: hidden; + border-radius: 16px; + + & > * { + margin-bottom: 2px; + border-radius: 4px; + overflow: hidden; + } + + &:has(+ .account-metadata-box) { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + } + + + .account-metadata-box { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom-left-radius: 16px; + border-bottom-right-radius: 16px; + } +} + .account-container .profile-metadata { display: flex; /* flex-wrap: wrap; */ gap: 2px; - border-radius: 16px; overflow: hidden; overflow-x: auto; } @@ -235,12 +257,11 @@ margin: 0; } -.account-container .common-followers p { +.account-container .common-followers { font-size: 90%; color: var(--text-insignificant-color); - border-top: 1px solid var(--outline-color); - border-bottom: 1px solid var(--outline-color); - padding: 8px 0; + background-color: var(--bg-faded-color); + padding: 8px 12px; margin: 0; } @@ -261,6 +282,74 @@ opacity: 0.5; } +@keyframes swoosh-bg-image { + 0% { + background-position: -320px 0; + opacity: 0.25; + } + 100% { + background-position: 0 0; + opacity: 1; + } +} +.account-container .posting-stats { + font-size: 90%; + color: var(--text-insignificant-color); + background-color: var(--bg-faded-color); + padding: 8px 12px; + --size: 8px; + --original-color: var(--link-color); + + .posting-stats-bar { + height: var(--size); + border-radius: var(--size); + overflow: hidden; + margin: 8px 0; + box-shadow: inset 0 0 0 1px var(--outline-color), + inset 0 0 0 1.5px var(--bg-blur-color); + background-color: var(--bg-color); + background-repeat: no-repeat; + animation: swoosh-bg-image 0.3s ease-in-out 0.3s both; + background-image: linear-gradient( + to right, + var(--original-color) 0%, + var(--original-color) var(--originals-percentage), + var(--reply-to-color) var(--originals-percentage), + var(--reply-to-color) var(--replies-percentage), + var(--reblog-color) var(--replies-percentage), + var(--reblog-color) 100% + ); + } + + .posting-stats-legends { + font-size: 12px; + text-transform: uppercase; + } + + .posting-stats-legend-item { + display: inline-block; + width: var(--size); + height: var(--size); + border-radius: var(--size); + background-color: var(--text-insignificant-color); + vertical-align: middle; + margin: 0 4px 2px; + /* border: 1px solid var(--outline-color); */ + box-shadow: inset 0 0 0 1px var(--outline-color), + inset 0 0 0 1.5px var(--bg-blur-color); + + &.posting-stats-legend-item-originals { + background-color: var(--original-color); + } + &.posting-stats-legend-item-replies { + background-color: var(--reply-to-color); + } + &.posting-stats-legend-item-boosts { + background-color: var(--reblog-color); + } + } +} + @keyframes shine { 0% { left: -100%; diff --git a/src/components/account-info.jsx b/src/components/account-info.jsx index 9a9ddb82..f7b04756 100644 --- a/src/components/account-info.jsx +++ b/src/components/account-info.jsx @@ -357,94 +357,99 @@ function AccountInfo({ __html: enhanceContent(note, { emojis }), }} /> - {fields?.length > 0 && ( -
- {fields.map(({ name, value, verifiedAt }, i) => ( -
- - {' '} - {!!verifiedAt && } - -

-

- ))} -
- )} -

- { - states.showAccount = false; - states.showGenericAccounts = { - heading: 'Followers', - fetchAccounts: fetchFollowers, - }; - }} - > - - {shortenNumber(followersCount)} - {' '} - Followers - - { - states.showAccount = false; - states.showGenericAccounts = { - heading: 'Following', - fetchAccounts: fetchFollowing, - }; - }} - > - - {shortenNumber(followingCount)} - {' '} - Following -
-
- { - hideAllModals(); - } - } - > - - {shortenNumber(statusesCount)} - {' '} - Posts - - {!!createdAt && ( -

- Joined{' '} - +
+ {fields?.length > 0 && ( + )} -

+
+ { + states.showAccount = false; + states.showGenericAccounts = { + heading: 'Followers', + fetchAccounts: fetchFollowers, + }; + }} + > + + {shortenNumber(followersCount)} + {' '} + Followers + + { + states.showAccount = false; + states.showGenericAccounts = { + heading: 'Following', + fetchAccounts: fetchFollowing, + }; + }} + > + + {shortenNumber(followingCount)} + {' '} + Following +
+
+ { + hideAllModals(); + } + } + > + + {shortenNumber(statusesCount)} + {' '} + Posts + + {!!createdAt && ( +
+ Joined{' '} + +
+ )} +
+
@@ -454,7 +459,9 @@ function AccountInfo({ ); } -function RelatedActions({ info, instance, authenticated }) { +const FAMILIAR_FOLLOWERS_LIMIT = 10; + +function RelatedActions({ info, instance, authenticated, standalone }) { if (!info) return null; const { masto: currentMasto, @@ -466,6 +473,7 @@ function RelatedActions({ info, instance, authenticated }) { const [relationshipUIState, setRelationshipUIState] = useState('default'); const [relationship, setRelationship] = useState(null); const [familiarFollowers, setFamiliarFollowers] = useState([]); + const [postingStats, setPostingStats] = useState(); const { id, acct, url, username, locked, lastStatusAt, note, fields } = info; const accountID = useRef(id); @@ -526,12 +534,11 @@ function RelatedActions({ info, instance, authenticated }) { setRelationshipUIState('loading'); setFamiliarFollowers([]); + setPostingStats(null); const fetchRelationships = currentMasto.v1.accounts.fetchRelationships([ currentID, ]); - const fetchFamiliarFollowers = - currentMasto.v1.accounts.fetchFamiliarFollowers(currentID); try { const relationships = await fetchRelationships; @@ -542,9 +549,55 @@ function RelatedActions({ info, instance, authenticated }) { if (!relationship.following) { try { + const fetchFamiliarFollowers = + currentMasto.v1.accounts.fetchFamiliarFollowers(currentID); + const fetchStatuses = currentMasto.v1.accounts + .listStatuses(currentID, { + limit: 20, + }) + .next(); + const followers = await fetchFamiliarFollowers; console.log('fetched familiar followers', followers); - setFamiliarFollowers(followers[0].accounts.slice(0, 10)); + setFamiliarFollowers(followers[0].accounts); + + if (standalone) return; + + const { value: statuses } = await fetchStatuses; + console.log('fetched statuses', statuses); + const stats = { + total: statuses.length, + originals: 0, + replies: 0, + boosts: 0, + }; + // Categories statuses by type + // - Original posts (not replies to others) + // - Threads (self-replies + 1st original post) + // - Boosts (reblogs) + // - Replies (not-self replies) + statuses.forEach((status) => { + if (status.reblog) { + stats.boosts++; + } else if ( + status.inReplyToAccountId !== currentID && + !!status.inReplyToId + ) { + stats.replies++; + } else { + stats.originals++; + } + }); + + // Count days since last post + stats.daysSinceLastPost = Math.ceil( + (Date.now() - + new Date(statuses[statuses.length - 1].createdAt)) / + 86400000, + ); + + console.log('posting stats', stats); + setPostingStats(stats); } catch (e) { console.error(e); } @@ -571,40 +624,109 @@ function RelatedActions({ info, instance, authenticated }) { const [showTranslatedBio, setShowTranslatedBio] = useState(false); const [showAddRemoveLists, setShowAddRemoveLists] = useState(false); + const hasFamiliarFollowers = familiarFollowers?.length > 0; + const hasPostingStats = postingStats?.total >= 3; + return ( <> -